From 5eb20f81d9568284dca735e4f770f41a48aa5660 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Fri, 8 Jun 2018 11:16:07 -0700 Subject: [PATCH 001/263] Consistently use ParseHashV to validate hash inputs in rpc ParseHashV validates the length and encoding of the string and throws an informative RPC error on failure, which is as good or better than these alternative calls. Note I switched ParseHashV to check string length first, because IsHex tests that the length is even, and an error like: "must be of length 64 (not 63, for X)" is much more informative than "must be hexadecimal string (not X)" --- src/rpc/blockchain.cpp | 25 +++++++------------ src/rpc/mining.cpp | 4 +-- src/rpc/rawtransaction.cpp | 6 ++--- src/rpc/server.cpp | 12 +++------ src/wallet/rpcdump.cpp | 3 +-- src/wallet/rpcwallet.cpp | 20 +++++---------- .../mining_prioritisetransaction.py | 3 ++- test/functional/p2p_compactblocks.py | 2 +- test/functional/p2p_sendheaders.py | 2 +- test/functional/rpc_blockchain.py | 8 ++++-- test/functional/rpc_rawtransaction.py | 12 +++++---- test/functional/rpc_txoutproof.py | 8 +++++- test/functional/wallet_basic.py | 8 +++++- test/functional/wallet_listsinceblock.py | 4 ++- 14 files changed, 58 insertions(+), 59 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f70d506e13..b809fd0f5d 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -252,7 +252,7 @@ static UniValue waitforblock(const JSONRPCRequest& request) ); int timeout = 0; - uint256 hash = uint256S(request.params[0].get_str()); + uint256 hash(ParseHashV(request.params[0], "blockhash")); if (!request.params[1].isNull()) timeout = request.params[1].get_int(); @@ -706,8 +706,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) LOCK(cs_main); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "hash")); bool fVerbose = true; if (!request.params[1].isNull()) @@ -800,8 +799,7 @@ static UniValue getblock(const JSONRPCRequest& request) LOCK(cs_main); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); int verbosity = 1; if (!request.params[1].isNull()) { @@ -1033,8 +1031,7 @@ UniValue gettxout(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "txid")); int n = request.params[1].get_int(); COutPoint out(hash, n); bool fMempool = true; @@ -1442,8 +1439,7 @@ static UniValue preciousblock(const JSONRPCRequest& request) + HelpExampleRpc("preciousblock", "\"blockhash\"") ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); CBlockIndex* pblockindex; { @@ -1478,8 +1474,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request) + HelpExampleRpc("invalidateblock", "\"blockhash\"") ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); CValidationState state; { @@ -1518,8 +1513,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) + HelpExampleRpc("reconsiderblock", "\"blockhash\"") ); - std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + uint256 hash(ParseHashV(request.params[0], "blockhash")); { LOCK(cs_main); @@ -1572,7 +1566,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) LOCK(cs_main); pindex = chainActive.Tip(); } else { - uint256 hash = uint256S(request.params[1].get_str()); + uint256 hash(ParseHashV(request.params[1], "blockhash")); LOCK(cs_main); pindex = LookupBlockIndex(hash); if (!pindex) { @@ -1711,8 +1705,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) pindex = chainActive[height]; } else { - const std::string strHash = request.params[0].get_str(); - const uint256 hash(uint256S(strHash)); + const uint256 hash(ParseHashV(request.params[0], "hash_or_height")); pindex = LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 85b864e6b9..c95145b204 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -247,7 +247,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) LOCK(cs_main); - uint256 hash = ParseHashStr(request.params[0].get_str(), "txid"); + uint256 hash(ParseHashV(request.params[0], "txid")); CAmount nAmount = request.params[2].get_int64(); if (!(request.params[1].isNull() || request.params[1].get_real() == 0)) { @@ -456,7 +456,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) // Format: std::string lpstr = lpval.get_str(); - hashWatchedChain.SetHex(lpstr.substr(0, 64)); + hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid"); nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); } else diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3b3f43edea..9f94307949 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -229,9 +229,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) UniValue txids = request.params[0].get_array(); for (unsigned int idx = 0; idx < txids.size(); idx++) { const UniValue& txid = txids[idx]; - if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str()); - uint256 hash(uint256S(txid.get_str())); + uint256 hash(ParseHashV(txid, "txid")); if (setTxids.count(hash)) throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str()); setTxids.insert(hash); @@ -242,7 +240,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) uint256 hashBlock; if (!request.params[1].isNull()) { LOCK(cs_main); - hashBlock = uint256S(request.params[1].get_str()); + hashBlock = ParseHashV(request.params[1], "blockhash"); pblockindex = LookupBlockIndex(hashBlock); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 10040b1255..85383eb3bc 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -117,16 +117,12 @@ CAmount AmountFromValue(const UniValue& value) uint256 ParseHashV(const UniValue& v, std::string strName) { - std::string strHex; - if (v.isStr()) - strHex = v.get_str(); + std::string strHex(v.get_str()); + if (64 != strHex.length()) + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex)); if (!IsHex(strHex)) // Note: IsHex("") is false throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); - if (64 != strHex.length()) - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length())); - uint256 result; - result.SetHex(strHex); - return result; + return uint256S(strHex); } uint256 ParseHashO(const UniValue& o, std::string strKey) { diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d09af1dbd1..d08b80cc20 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -416,8 +416,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - uint256 hash; - hash.SetHex(request.params[0].get_str()); + uint256 hash(ParseHashV(request.params[0], "txid")); std::vector vHash; vHash.push_back(hash); std::vector vHashOut; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 456f08bc14..fec8f69019 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2231,9 +2231,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request) isminefilter filter = ISMINE_SPENDABLE; if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { - uint256 blockId; + uint256 blockId(ParseHashV(request.params[0], "blockhash")); - blockId.SetHex(request.params[0].get_str()); paltindex = pindex = LookupBlockIndex(blockId); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -2362,8 +2361,7 @@ static UniValue gettransaction(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - uint256 hash; - hash.SetHex(request.params[0].get_str()); + uint256 hash(ParseHashV(request.params[0], "txid")); isminefilter filter = ISMINE_SPENDABLE; if(!request.params[1].isNull()) @@ -2430,8 +2428,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - uint256 hash; - hash.SetHex(request.params[0].get_str()); + uint256 hash(ParseHashV(request.params[0], "txid")); if (!pwallet->mapWallet.count(hash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); @@ -2836,17 +2833,13 @@ static UniValue lockunspent(const JSONRPCRequest& request) {"vout", UniValueType(UniValue::VNUM)}, }); - const std::string& txid = find_value(o, "txid").get_str(); - if (!IsHex(txid)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); - } - + const uint256 txid(ParseHashO(o, "txid")); const int nOutput = find_value(o, "vout").get_int(); if (nOutput < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); } - const COutPoint outpt(uint256S(txid), nOutput); + const COutPoint outpt(txid, nOutput); const auto it = pwallet->mapWallet.find(outpt.hash); if (it == pwallet->mapWallet.end()) { @@ -3701,8 +3694,7 @@ static UniValue bumpfee(const JSONRPCRequest& request) } RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ}); - uint256 hash; - hash.SetHex(request.params[0].get_str()); + uint256 hash(ParseHashV(request.params[0], "txid")); // optional parameters CAmount totalFee = 0; diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py index 85f1af6682..e16e1e242f 100755 --- a/test/functional/mining_prioritisetransaction.py +++ b/test/functional/mining_prioritisetransaction.py @@ -24,7 +24,8 @@ def run_test(self): assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction, '', 0, 0, 0) # Test `prioritisetransaction` invalid `txid` - assert_raises_rpc_error(-1, "txid must be hexadecimal string", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0) + assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0) + assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000')", self.nodes[0].prioritisetransaction, txid='Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000', fee_delta=0) # Test `prioritisetransaction` invalid `dummy` txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000' diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index cb4c9867a3..36cd8f5b09 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -287,7 +287,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a block_hash = int(node.generate(1)[0], 16) # Store the raw block in our internal format. - block = FromHex(CBlock(), node.getblock("%02x" % block_hash, False)) + block = FromHex(CBlock(), node.getblock("%064x" % block_hash, False)) for tx in block.vtx: tx.calc_sha256() block.rehash() diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index 095cc4b734..ff377721cb 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -402,7 +402,7 @@ def test_nonnull_locators(self, test_node, inv_node): block_time += 9 - fork_point = self.nodes[0].getblock("%02x" % new_block_hashes[0])["previousblockhash"] + fork_point = self.nodes[0].getblock("%064x" % new_block_hashes[0])["previousblockhash"] fork_point = int(fork_point, 16) # Use getblocks/getdata diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 17e24453e5..a908596ab3 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -125,7 +125,9 @@ def _test_getchaintxstats(self): # Test `getchaintxstats` invalid `blockhash` assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getchaintxstats, blockhash=0) - assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0') + assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 1, for '0')", self.nodes[0].getchaintxstats, blockhash='0') + assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getchaintxstats, blockhash='ZZZ0000000000000000000000000000000000000000000000000000000000000') + assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getchaintxstats, blockhash='0000000000000000000000000000000000000000000000000000000000000000') blockhash = self.nodes[0].getblockhash(200) self.nodes[0].invalidateblock(blockhash) assert_raises_rpc_error(-8, "Block is not in main chain", self.nodes[0].getchaintxstats, blockhash=blockhash) @@ -206,7 +208,9 @@ def _test_gettxoutsetinfo(self): def _test_getblockheader(self): node = self.nodes[0] - assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "nonsense") + assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense") + assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844") + assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844") besthash = node.getbestblockhash() secondbesthash = node.getblockhash(199) diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 48b4a4a9db..a1bfb00e16 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -76,8 +76,9 @@ def run_test(self): txid = '1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000' assert_raises_rpc_error(-3, "Expected type array", self.nodes[0].createrawtransaction, 'foo', {}) assert_raises_rpc_error(-1, "JSON value is not an object as expected", self.nodes[0].createrawtransaction, ['foo'], {}) - assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{}], {}) - assert_raises_rpc_error(-8, "txid must be hexadecimal string", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {}) + assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].createrawtransaction, [{}], {}) + assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {}) + assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", self.nodes[0].createrawtransaction, [{'txid': 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844'}], {}) assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid}], {}) assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': 'foo'}], {}) assert_raises_rpc_error(-8, "Invalid parameter, vout must be positive", self.nodes[0].createrawtransaction, [{'txid': txid, 'vout': -1}], {}) @@ -165,9 +166,10 @@ def run_test(self): # We should not get the tx if we provide an unrelated block assert_raises_rpc_error(-5, "No such transaction found", self.nodes[0].getrawtransaction, tx, True, block2) # An invalid block hash should raise the correct errors - assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, True) - assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal", self.nodes[0].getrawtransaction, tx, True, "foobar") - assert_raises_rpc_error(-8, "parameter 3 must be of length 64", self.nodes[0].getrawtransaction, tx, True, "abcd1234") + assert_raises_rpc_error(-1, "JSON value is not a string as expected", self.nodes[0].getrawtransaction, tx, True, True) + assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 6, for 'foobar')", self.nodes[0].getrawtransaction, tx, True, "foobar") + assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')", self.nodes[0].getrawtransaction, tx, True, "abcd1234") + assert_raises_rpc_error(-8, "parameter 3 must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].getrawtransaction, tx, True, "ZZZ0000000000000000000000000000000000000000000000000000000000000") assert_raises_rpc_error(-5, "Block hash not found", self.nodes[0].getrawtransaction, tx, True, "0000000000000000000000000000000000000000000000000000000000000000") # Undo the blocks and check in_active_chain self.nodes[0].invalidateblock(block1) diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index c52a7397dc..26abed414a 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -62,12 +62,18 @@ def run_test(self): txid_spent = txin_spent["txid"] txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2 + # Invalid txids + assert_raises_rpc_error(-8, "txid must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[2].gettxoutproof, ["00000000000000000000000000000000"], blockhash) + assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].gettxoutproof, ["ZZZ0000000000000000000000000000000000000000000000000000000000000"], blockhash) + # Invalid blockhashes + assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 32, for '00000000000000000000000000000000')", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000") + assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", self.nodes[2].gettxoutproof, [txid_spent], "ZZZ0000000000000000000000000000000000000000000000000000000000000") # We can't find the block from a fully-spent tx assert_raises_rpc_error(-5, "Transaction not yet in block", self.nodes[2].gettxoutproof, [txid_spent]) # We can get the proof if we specify the block assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent]) # We can't get the proof if we specify a non-existent block - assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "00000000000000000000000000000000") + assert_raises_rpc_error(-5, "Block not found", self.nodes[2].gettxoutproof, [txid_spent], "0000000000000000000000000000000000000000000000000000000000000000") # We can get the proof if the transaction is unspent assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent]) # We can get the proof if we provide a list of transactions and one of them is unspent. The ordering of the list should not matter. diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 9c58b84819..add7b7629d 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -122,9 +122,15 @@ def run_test(self): assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) - assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", + assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')", self.nodes[2].lockunspent, False, [{"txid": "0000000000000000000000000000000000", "vout": 0}]) + assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", + self.nodes[2].lockunspent, False, + [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) + assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", + self.nodes[2].lockunspent, False, + [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index 63c179411c..a49be78f2b 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -50,8 +50,10 @@ def test_invalid_blockhash(self): "42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4") assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, "0000000000000000000000000000000000000000000000000000000000000000") - assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock, + assert_raises_rpc_error(-8, "blockhash must be of length 64 (not 11, for 'invalid-hex')", self.nodes[0].listsinceblock, "invalid-hex") + assert_raises_rpc_error(-8, "blockhash must be hexadecimal string (not 'Z000000000000000000000000000000000000000000000000000000000000000')", self.nodes[0].listsinceblock, + "Z000000000000000000000000000000000000000000000000000000000000000") def test_reorg(self): ''' From a3197c5294df4711bab0ff6dcdd061ceab115c7d Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Mon, 20 Aug 2018 15:24:55 -0400 Subject: [PATCH 002/263] Disable wallet and address book Qt tests on macOS minimal platform macOS Qt minimal platform is frequently broken, and these are currently failing with Qt 5.11.1. The tests do pass when run on the full cocoa platform (with `test_bitcoin-qt -platform cocoa`). --- src/qt/test/addressbooktests.cpp | 12 ++++++++++++ src/qt/test/wallettests.cpp | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index c3d33c76d4..3525846044 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -139,5 +140,16 @@ void TestAddAddressesToSendBook() void AddressBookTests::addressBookTests() { +#ifdef Q_OS_MAC + if (QApplication::platformName() == "minimal") { + // Disable for mac on "minimal" platform to avoid crashes inside the Qt + // framework when it tries to look up unimplemented cocoa functions, + // and fails to handle returned nulls + // (https://bugreports.qt.io/browse/QTBUG-49686). + QWARN("Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build."); + return; + } +#endif TestAddAddressesToSendBook(); } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index c314dadde4..9598d64845 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -243,5 +243,16 @@ void TestGUI() void WalletTests::walletTests() { +#ifdef Q_OS_MAC + if (QApplication::platformName() == "minimal") { + // Disable for mac on "minimal" platform to avoid crashes inside the Qt + // framework when it tries to look up unimplemented cocoa functions, + // and fails to handle returned nulls + // (https://bugreports.qt.io/browse/QTBUG-49686). + QWARN("Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke " + "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build."); + return; + } +#endif TestGUI(); } From 66b3fc543706aad1aaccc403b4ee08f65fa5d17b Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Wed, 22 Aug 2018 23:29:01 +0000 Subject: [PATCH 003/263] Skip stale tip checking if outbound connections are off or if reindexing. --- src/net.h | 3 +++ src/net_processing.cpp | 7 +++---- src/net_processing.h | 5 ++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/net.h b/src/net.h index f9cfea59b7..e074dbb624 100644 --- a/src/net.h +++ b/src/net.h @@ -149,6 +149,7 @@ class CConnman nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections); + m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing; nMaxAddnode = connOptions.nMaxAddnode; nMaxFeeler = connOptions.nMaxFeeler; nBestHeight = connOptions.nBestHeight; @@ -174,6 +175,7 @@ class CConnman void Stop(); void Interrupt(); bool GetNetworkActive() const { return fNetworkActive; }; + bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; void SetNetworkActive(bool active); void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false); bool CheckIncomingNonce(uint64_t nonce); @@ -416,6 +418,7 @@ class CConnman int nMaxOutbound; int nMaxAddnode; int nMaxFeeler; + bool m_use_addrman_outgoing; std::atomic nBestHeight; CClientUIInterface* clientInterface; NetEventsInterface* m_msgproc; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 88999ba735..2a0ba3970d 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3166,8 +3166,6 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) NodeId worst_peer = -1; int64_t oldest_block_announcement = std::numeric_limits::max(); - LOCK(cs_main); - connman->ForEachNode([&](CNode* pnode) { AssertLockHeld(cs_main); @@ -3215,6 +3213,8 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams) { + LOCK(cs_main); + if (connman == nullptr) return; int64_t time_in_seconds = GetTime(); @@ -3222,10 +3222,9 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params EvictExtraOutboundPeers(time_in_seconds); if (time_in_seconds > m_stale_tip_check_time) { - LOCK(cs_main); // Check whether our tip is stale, and if so, allow using an extra // outbound peer - if (TipMayBeStale(consensusParams)) { + if (!fImporting && !fReindex && connman->GetNetworkActive() && connman->GetUseAddrmanOutgoing() && TipMayBeStale(consensusParams)) { LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update); connman->SetTryNewOutboundPeer(true); } else if (connman->GetTryNewOutboundPeer()) { diff --git a/src/net_processing.h b/src/net_processing.h index 7caefc80ca..01b8e97075 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -9,6 +9,9 @@ #include #include #include +#include + +extern CCriticalSection cs_main; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; @@ -65,7 +68,7 @@ class PeerLogicValidation final : public CValidationInterface, public NetEventsI /** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */ void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams); /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ - void EvictExtraOutboundPeers(int64_t time_in_seconds); + void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); private: int64_t m_stale_tip_check_time; //! Next time to check for stale tip From 00c6306a61aafc8161155bc555cca2d0998c6a5d Mon Sep 17 00:00:00 2001 From: practicalswift Date: Thu, 30 Aug 2018 22:19:28 +0200 Subject: [PATCH 004/263] Remove RUN_BENCH logic --- .travis.yml | 2 -- .travis/test_06_script.sh | 6 ------ 2 files changed, 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8819d38914..b2ad5a5f66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ env: - MAKEJOBS=-j3 - RUN_UNIT_TESTS=true - RUN_FUNCTIONAL_TESTS=true - - RUN_BENCH=false # Set to true for any one job that has debug enabled, to quickly check bench is not crashing or hitting assertions - DOCKER_NAME_TAG=ubuntu:18.04 - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - CCACHE_SIZE=100M @@ -113,7 +112,6 @@ jobs: HOST=x86_64-unknown-linux-gnu PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" NO_DEPENDS=1 - RUN_BENCH=true RUN_FUNCTIONAL_TESTS=false # Disabled for now, can be combined with the other x86_64 linux NO_DEPENDS job when functional tests pass the sanitizers GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=undefined CC=clang CXX=clang++" diff --git a/.travis/test_06_script.sh b/.travis/test_06_script.sh index e5fea81187..6b7ec78478 100755 --- a/.travis/test_06_script.sh +++ b/.travis/test_06_script.sh @@ -50,12 +50,6 @@ if [ "$RUN_UNIT_TESTS" = "true" ]; then END_FOLD fi -if [ "$RUN_BENCH" = "true" ]; then - BEGIN_FOLD bench - DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib $OUTDIR/bin/bench_bitcoin -scaling=0.001 - END_FOLD -fi - if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude feature_pruning,feature_dbcrash" fi From dfef0df8406528915aaa718e761ce9eaab14ee37 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Tue, 28 Aug 2018 13:50:41 +0200 Subject: [PATCH 005/263] tests: Dry run bench_bitcoin (-evals=1 -scaling=0: <1 second running time) as part "make check" to allow for quick identification of assertion/sanitizer failures in benchmarking code --- src/Makefile.test.include | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index abfd66efad..5da531768a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -154,7 +154,15 @@ CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) +if TARGET_WINDOWS bitcoin_test: $(TEST_BINARY) +else +if ENABLE_BENCH +bitcoin_test: $(TEST_BINARY) $(BENCH_BINARY) +else +bitcoin_test: $(TEST_BINARY) +endif +endif bitcoin_test_check: $(TEST_BINARY) FORCE $(MAKE) check-TESTS TESTS=$^ @@ -167,6 +175,13 @@ check-local: $(BITCOIN_TESTS:.cpp=.cpp.test) $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py @echo "Running test/util/rpcauth-test.py..." $(PYTHON) $(top_builddir)/test/util/rpcauth-test.py +if TARGET_WINDOWS +else +if ENABLE_BENCH + @echo "Running bench/bench_bitcoin -evals=1 -scaling=0..." + $(BENCH_BINARY) -evals=1 -scaling=0 > /dev/null +endif +endif $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check From eb494125624eb3d311c6b2e45ce403c61faddd62 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Thu, 6 Sep 2018 09:59:42 -0400 Subject: [PATCH 006/263] doc/descriptors.md tweaks Add some implementation details, and tweak phrasing in examples section to be more explicit about how script expressions are used for matching. --- doc/descriptors.md | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/doc/descriptors.md b/doc/descriptors.md index c23ac06e8f..d97e838d7e 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -22,19 +22,19 @@ Output descriptors currently support: ## Examples -- `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` represents a P2PK output. -- `pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)` represents a P2PKH output. -- `wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)` represents a P2WPKH output. -- `sh(wpkh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))` represents a P2SH-P2WPKH output. -- `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` represents a P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH output. -- `sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)))` represents a (overly complicated) P2SH-P2WSH-P2PKH output. -- `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` represents a bare *1-of-2* multisig. -- `sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))` represents a P2SH *2-of-2* multisig. -- `wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))` represents a P2WSH *2-of-3* multisig. -- `sh(wsh(multi(1,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e)))` represents a P2SH-P2WSH *1-of-3* multisig. -- `pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8)` refers to a single P2PK output, using the public key part from the specified xpub. -- `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)` refers to a single P2PKH output, using child key *1'/2* of the specified xpub. -- `wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/0/*))` refers to a chain of *1-of-2* P2WSH multisig outputs, using public keys taken from two HD chains with corresponding derivation paths. +- `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` matches a P2PK output with the specified public key. +- `pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)` matches a P2PKH output with the specified public key. +- `wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9)` matches a P2WPKH output with the specified public key. +- `sh(wpkh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))` matches a P2SH-P2WPKH output with the specified public key. +- `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` matches any P2PK, P2PKH, P2WPKH, or P2SH-P2WPKH output with the specified public key. +- `sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)))` matches an (overly complicated) P2SH-P2WSH-P2PKH output with the specified public key. +- `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` matches a bare *1-of-2* multisig output with keys in the specified order. +- `sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe))` matches a P2SH *2-of-2* multisig output with keys in the specified order. +- `wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))` matches a P2WSH *2-of-3* multisig output with keys in the specified order. +- `sh(wsh(multi(1,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e)))` matches a P2SH-P2WSH *1-of-3* multisig output with keys in the specified order. +- `pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8)` matches a P2PK output with the public key of the specified xpub. +- `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)` matches a P2PKH output with child key *1'/2* of the specified xpub. +- `wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))` matches any *1-of-2* P2WSH multisig output where the first multisig key is the *1/0/`i`* child of the first specified xpub and the second multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default). ## Reference @@ -91,6 +91,14 @@ on Bitcoin's OP_CHECKMULTISIG opcode. To support these, we introduce the multisig policy, where any *k* out of the *n* provided public keys must sign. +Key order is significant. A `multi()` expression will only match multisig +scripts with keys in the specified order. Also, to prevent a combinatorial +explosion of the search space, if more than one `multi()` key arguments is a +BIP32 wildcard path ending in `/*` or `*'`, the `multi()` expression only +matches multisig scripts with the `i`th child key from each wildcard path in +lockstep, rather than scripts with any combination of child keys from each +wildcard path. + ### BIP32 derived keys and chains Most modern wallet software and hardware uses keys that are derived using @@ -101,7 +109,7 @@ path consists of a sequence of 0 or more integers (in the range *0..231-1*) each optionally followed by `'` or `h`, and separated by `/` characters. The string may optionally end with the literal `/*` or `/*'` (or `/*h`) to refer to all unhardened or hardened -child keys instead. +child keys in a configurable range (by default `0-1000`, inclusive). Whenever a public key is described using a hardened derivation step, the script cannot be computed without access to the corresponding private @@ -119,6 +127,6 @@ steps, or for dumping wallet descriptors including private key material. In order to easily represent the sets of scripts currently supported by existing Bitcoin Core wallets, a convenience function `combo` is -provided, which takes as input a public key, and constructs the P2PK, -P2PKH, P2WPKH, and P2SH-P2WPH scripts for that key. In case the key is -uncompressed, it only constructs P2PK and P2PKH. +provided, which takes as input a public key, and matches P2PK, +P2PKH, P2WPKH, or P2SH-P2WPH scripts for that key. In case the key is +uncompressed, it only matches the P2PK or P2PKH scripts. \ No newline at end of file From 3387bb0829c146826ad1fa2ba9bfd64fcd9a215f Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Thu, 30 Aug 2018 01:44:21 +0800 Subject: [PATCH 007/263] travis: avoid timeout without saving caches, also enable all qt --- .travis.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8819d38914..f8b62e08e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ install: before_script: - set -o errexit; source .travis/test_05_before_script.sh script: - - set -o errexit; source .travis/test_06_script.sh + - if [ $SECONDS -gt 1200 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script.sh; fi after_script: - echo $TRAVIS_COMMIT_RANGE - echo $TRAVIS_COMMIT_LOG @@ -57,8 +57,7 @@ jobs: - stage: test env: >- HOST=arm-linux-gnueabihf - PACKAGES="g++-arm-linux-gnueabihf" - DEP_OPTS="NO_QT=1" + PACKAGES="python3 g++-arm-linux-gnueabihf" RUN_UNIT_TESTS=false RUN_FUNCTIONAL_TESTS=false GOAL="install" @@ -70,24 +69,21 @@ jobs: env: >- HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" - DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32" - GOAL="install" - BITCOIN_CONFIG="--enable-reduce-exports" + GOAL="deploy" + BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" # Win64 - stage: test env: >- HOST=x86_64-w64-mingw32 - DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" - GOAL="install" - BITCOIN_CONFIG="--enable-reduce-exports" + GOAL="deploy" + BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests" # 32-bit + dash - stage: test env: >- HOST=i686-pc-linux-gnu PACKAGES="g++-multilib python3-zmq" - DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" CONFIG_SHELL="/bin/dash" @@ -133,5 +129,5 @@ jobs: OSX_SDK=10.11 RUN_UNIT_TESTS=false RUN_FUNCTIONAL_TESTS=false - GOAL="all deploy" + GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror" From fa511e8dad87ddee7bf03b82f2ed69e546021004 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 27 Jul 2018 14:35:28 -0400 Subject: [PATCH 008/263] Pass tx pool reference into CheckSequenceLocks --- src/test/miner_tests.cpp | 4 ++-- src/txmempool.cpp | 2 +- src/validation.cpp | 8 ++++---- src/validation.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 3eb8aa14fd..354ca7507e 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -92,8 +92,8 @@ static CBlockIndex CreateBlockIndex(int nHeight) static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - LOCK(mempool.cs); - return CheckSequenceLocks(tx, flags); + LOCK(::mempool.cs); + return CheckSequenceLocks(::mempool, tx, flags); } // Test suite for ancestor feerate transaction selection. diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 3ad93342c4..34a1e539df 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -498,7 +498,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem const CTransaction& tx = it->GetTx(); LockPoints lp = it->GetLockPoints(); bool validLP = TestLockPointValidity(&lp); - if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) { + if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(*this, tx, flags, &lp, validLP)) { // Note if CheckSequenceLocks fails the LockPoints may still be invalid // So it's critical that we remove the tx and not depend on the LockPoints. txToRemove.insert(it); diff --git a/src/validation.cpp b/src/validation.cpp index d4a84c53b5..259ee891a9 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -361,10 +361,10 @@ bool TestLockPointValidity(const LockPoints* lp) return true; } -bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) +bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints) { AssertLockHeld(cs_main); - AssertLockHeld(mempool.cs); + AssertLockHeld(pool.cs); CBlockIndex* tip = chainActive.Tip(); assert(tip != nullptr); @@ -387,7 +387,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool } else { // pcoinsTip contains the UTXO set for chainActive.Tip() - CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool); + CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool); std::vector prevheights; prevheights.resize(tx.vin.size()); for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { @@ -679,7 +679,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // be mined yet. // Must keep pool.cs for this unless we change CheckSequenceLocks to take a // CoinsViewCache instead of create its own - if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) + if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); CAmount nFees = 0; diff --git a/src/validation.h b/src/validation.h index 3df6456eca..d21f0606f9 100644 --- a/src/validation.h +++ b/src/validation.h @@ -347,7 +347,7 @@ bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_mai * * See consensus/consensus.h for flag definitions. */ -bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** * Closure representing one script verification From f1bd03eb013b96ff040a8f835e4137fbd2a38cda Mon Sep 17 00:00:00 2001 From: mruddy <6440430+mruddy@users.noreply.github.com> Date: Sat, 30 Jun 2018 10:32:33 -0400 Subject: [PATCH 009/263] [depends, zmq, doc] upgrade zeromq to 4.2.5 and avoid deprecated zeromq api functions --- depends/packages/zeromq.mk | 4 ++-- .../0001-fix-build-with-older-mingw64.patch | 16 +++++++-------- .../0002-disable-pthread_set_name_np.patch | 20 +++++++++---------- doc/build-unix.md | 4 ++-- doc/dependencies.md | 2 +- doc/zmq.md | 6 ++++-- src/zmq/zmqnotificationinterface.cpp | 8 ++++++-- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk index d5fd1f39ab..c9068e83a5 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -1,8 +1,8 @@ package=zeromq -$(package)_version=4.2.3 +$(package)_version=4.2.5 $(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=8f1e2b2aade4dbfde98d82366d61baef2f62e812530160d2e6d0a5bb24e40bc0 +$(package)_sha256_hash=cc9090ba35713d59bb2f7d7965f877036c49c5558ea0c290b0dcc6f2a17e489f $(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch define $(package)_set_vars diff --git a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch index a6c508fb8a..b911ac5672 100644 --- a/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch +++ b/depends/patches/zeromq/0001-fix-build-with-older-mingw64.patch @@ -1,6 +1,6 @@ -From 1a159c128c69a42d90819375c06a39994f3fbfc1 Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Tue, 28 Nov 2017 20:33:25 -0500 +From f6866b0f166ad168618aae64c7fbee8775d3eb23 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:44:58 -0400 Subject: [PATCH] fix build with older mingw64 --- @@ -8,10 +8,10 @@ Subject: [PATCH] fix build with older mingw64 1 file changed, 7 insertions(+) diff --git a/src/windows.hpp b/src/windows.hpp -index 99e889d..e69038e 100644 +index 6c3839fd..2c32ec79 100644 --- a/src/windows.hpp +++ b/src/windows.hpp -@@ -55,6 +55,13 @@ +@@ -58,6 +58,13 @@ #include #include #include @@ -23,8 +23,8 @@ index 99e889d..e69038e 100644 +#include +#endif #include - + #if !defined __MINGW32__ --- -2.7.4 +-- +2.17.1 diff --git a/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch index d220b54f3e..022e311977 100644 --- a/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch +++ b/depends/patches/zeromq/0002-disable-pthread_set_name_np.patch @@ -1,6 +1,6 @@ -From 6e6b47d5ab381c3df3b30bb0b0a6cf210dfb1eba Mon Sep 17 00:00:00 2001 -From: Cory Fields -Date: Mon, 5 Mar 2018 14:22:05 -0500 +From c9bbdd6581d07acfe8971e4bcebe278a3676cf03 Mon Sep 17 00:00:00 2001 +From: mruddy <6440430+mruddy@users.noreply.github.com> +Date: Sat, 30 Jun 2018 09:57:18 -0400 Subject: [PATCH] disable pthread_set_name_np pthread_set_name_np adds a Glibc requirement on >= 2.12. @@ -9,21 +9,21 @@ pthread_set_name_np adds a Glibc requirement on >= 2.12. 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/thread.cpp b/src/thread.cpp -index 4fc59c3e..c3fdfd46 100644 +index a1086b0c..9943f354 100644 --- a/src/thread.cpp +++ b/src/thread.cpp -@@ -220,7 +220,7 @@ void zmq::thread_t::setThreadName(const char *name_) +@@ -307,7 +307,7 @@ void zmq::thread_t::setThreadName (const char *name_) */ if (!name_) return; - +#if 0 #if defined(ZMQ_HAVE_PTHREAD_SETNAME_1) - int rc = pthread_setname_np(name_); - if(rc) return; -@@ -233,6 +233,8 @@ void zmq::thread_t::setThreadName(const char *name_) + int rc = pthread_setname_np (name_); + if (rc) +@@ -323,6 +323,8 @@ void zmq::thread_t::setThreadName (const char *name_) #elif defined(ZMQ_HAVE_PTHREAD_SET_NAME) - pthread_set_name_np(descriptor, name_); + pthread_set_name_np (descriptor, name_); #endif +#endif + return; @@ -31,5 +31,5 @@ index 4fc59c3e..c3fdfd46 100644 #endif -- -2.11.1 +2.17.1 diff --git a/doc/build-unix.md b/doc/build-unix.md index 337de12b8d..dfeb8ba260 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -47,7 +47,7 @@ Optional dependencies: protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) - libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.x) + libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.0.0) For the versions used, see [dependencies.md](dependencies.md) @@ -93,7 +93,7 @@ Optional (see --with-miniupnpc and --enable-upnp-default): sudo apt-get install libminiupnpc-dev -ZMQ dependencies (provides ZMQ API 4.x): +ZMQ dependencies (provides ZMQ API): sudo apt-get install libzmq3-dev diff --git a/doc/dependencies.md b/doc/dependencies.md index 3fc7aecba8..d777aaf66f 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -26,5 +26,5 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct | Qt | [5.9.6](https://download.qt.io/official_releases/qt/) | 5.x | No | | | | XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L87) (Linux only) | | xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L86) (Linux only) | -| ZeroMQ | [4.2.3](https://github.com/zeromq/libzmq/releases) | | No | | | +| ZeroMQ | [4.2.5](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | | | zlib | [1.2.11](https://zlib.net/) | | | | No | diff --git a/doc/zmq.md b/doc/zmq.md index 5d67df9d22..a1a506f2e7 100644 --- a/doc/zmq.md +++ b/doc/zmq.md @@ -33,8 +33,10 @@ buffering or reassembly. ## Prerequisites -The ZeroMQ feature in Bitcoin Core requires ZeroMQ API version 4.x or -newer. Typically, it is packaged by distributions as something like +The ZeroMQ feature in Bitcoin Core requires the ZeroMQ API >= 4.0.0 +[libzmq](https://github.com/zeromq/libzmq/releases). +For version information, see [dependencies.md](dependencies.md). +Typically, it is packaged by distributions as something like *libzmq3-dev*. The C++ wrapper for ZeroMQ is *not* needed. In order to run the example Python client scripts in contrib/ one must diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 8cbc969972..1d9f86d450 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -81,10 +81,14 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create() // Called at startup to conditionally set up ZMQ socket(s) bool CZMQNotificationInterface::Initialize() { + int major = 0, minor = 0, patch = 0; + zmq_version(&major, &minor, &patch); + LogPrint(BCLog::ZMQ, "zmq: version %d.%d.%d\n", major, minor, patch); + LogPrint(BCLog::ZMQ, "zmq: Initialize notification interface\n"); assert(!pcontext); - pcontext = zmq_init(1); + pcontext = zmq_ctx_new(); if (!pcontext) { @@ -127,7 +131,7 @@ void CZMQNotificationInterface::Shutdown() LogPrint(BCLog::ZMQ, " Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress()); notifier->Shutdown(); } - zmq_ctx_destroy(pcontext); + zmq_ctx_term(pcontext); pcontext = nullptr; } From ea3009ee942188750480ca6cc273b2b91cf77ded Mon Sep 17 00:00:00 2001 From: Pierre Rochard Date: Mon, 10 Sep 2018 20:49:17 -0400 Subject: [PATCH 010/263] wallet: Add walletdir arg unit tests --- build_msvc/test_bitcoin/test_bitcoin.vcxproj | 2 +- src/Makefile.test.include | 7 ++- src/wallet/test/init_test_fixture.cpp | 42 ++++++++++++++ src/wallet/test/init_test_fixture.h | 21 +++++++ src/wallet/test/init_tests.cpp | 58 ++++++++++++++++++++ 5 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 src/wallet/test/init_test_fixture.cpp create mode 100644 src/wallet/test/init_test_fixture.h create mode 100644 src/wallet/test/init_tests.cpp diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj index 444a2ed725..2316e473aa 100644 --- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj +++ b/build_msvc/test_bitcoin/test_bitcoin.vcxproj @@ -24,7 +24,7 @@ - + diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c4ee5f5fcc..7a36e216e1 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -110,11 +110,14 @@ BITCOIN_TESTS += \ wallet/test/psbt_wallet_tests.cpp \ wallet/test/wallet_tests.cpp \ wallet/test/wallet_crypto_tests.cpp \ - wallet/test/coinselector_tests.cpp + wallet/test/coinselector_tests.cpp \ + wallet/test/init_tests.cpp BITCOIN_TEST_SUITE += \ wallet/test/wallet_test_fixture.cpp \ - wallet/test/wallet_test_fixture.h + wallet/test/wallet_test_fixture.h \ + wallet/test/init_test_fixture.cpp \ + wallet/test/init_test_fixture.h endif test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp new file mode 100644 index 0000000000..1453029c9c --- /dev/null +++ b/src/wallet/test/init_test_fixture.cpp @@ -0,0 +1,42 @@ +// 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. + +#include + +#include + +InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName): BasicTestingSetup(chainName) +{ + std::string sep; + sep += fs::path::preferred_separator; + + m_datadir = SetDataDir("tempdir"); + m_cwd = fs::current_path(); + + m_walletdir_path_cases["default"] = m_datadir / "wallets"; + m_walletdir_path_cases["custom"] = m_datadir / "my_wallets"; + m_walletdir_path_cases["nonexistent"] = m_datadir / "path_does_not_exist"; + m_walletdir_path_cases["file"] = m_datadir / "not_a_directory.dat"; + m_walletdir_path_cases["trailing"] = m_datadir / "wallets" / sep; + m_walletdir_path_cases["trailing2"] = m_datadir / "wallets" / sep / sep; + + fs::current_path(m_datadir); + m_walletdir_path_cases["relative"] = "wallets"; + + fs::create_directories(m_walletdir_path_cases["default"]); + fs::create_directories(m_walletdir_path_cases["custom"]); + fs::create_directories(m_walletdir_path_cases["relative"]); + std::ofstream f(m_walletdir_path_cases["file"].BOOST_FILESYSTEM_C_STR); + f.close(); +} + +InitWalletDirTestingSetup::~InitWalletDirTestingSetup() +{ + fs::current_path(m_cwd); +} + +void InitWalletDirTestingSetup::SetWalletDir(const fs::path& walletdir_path) +{ + gArgs.ForceSetArg("-walletdir", walletdir_path.string()); +} \ No newline at end of file diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h new file mode 100644 index 0000000000..5684adbece --- /dev/null +++ b/src/wallet/test/init_test_fixture.h @@ -0,0 +1,21 @@ +// 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. + +#ifndef BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H +#define BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H + +#include + + +struct InitWalletDirTestingSetup: public BasicTestingSetup { + explicit InitWalletDirTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); + ~InitWalletDirTestingSetup(); + void SetWalletDir(const fs::path& walletdir_path); + + fs::path m_datadir; + fs::path m_cwd; + std::map m_walletdir_path_cases; +}; + +#endif // BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp new file mode 100644 index 0000000000..a1d1a287e8 --- /dev/null +++ b/src/wallet/test/init_tests.cpp @@ -0,0 +1,58 @@ +// 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. + +#include + +#include +#include + +#include +#include +#include + + +BOOST_FIXTURE_TEST_SUITE(init_tests, InitWalletDirTestingSetup) + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) +{ + SetWalletDir(m_walletdir_path_cases["default"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom) +{ + SetWalletDir(m_walletdir_path_cases["custom"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_does_not_exist) +{ + SetWalletDir(m_walletdir_path_cases["nonexistent"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_directory) +{ + SetWalletDir(m_walletdir_path_cases["file"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative) +{ + SetWalletDir(m_walletdir_path_cases["relative"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == false); +} + +BOOST_AUTO_TEST_SUITE_END() From 2d471636eb9160ab51b08e491e3f003f57adbc36 Mon Sep 17 00:00:00 2001 From: Pierre Rochard Date: Mon, 10 Sep 2018 20:50:42 -0400 Subject: [PATCH 011/263] wallet: Remove trailing separators from -walletdir arg --- src/wallet/init.cpp | 7 ++++++- src/wallet/test/init_tests.cpp | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index a299a4ee44..46983642f0 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -182,13 +182,18 @@ bool WalletInit::Verify() const if (gArgs.IsArgSet("-walletdir")) { fs::path wallet_dir = gArgs.GetArg("-walletdir", ""); - if (!fs::exists(wallet_dir)) { + boost::system::error_code error; + // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory + fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error); + if (error || !fs::exists(wallet_dir)) { return InitError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string())); } else if (!fs::is_directory(wallet_dir)) { return InitError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string())); + // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version } else if (!wallet_dir.is_absolute()) { return InitError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string())); } + gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string()); } LogPrintf("Using wallet directory %s\n", GetWalletDir().string()); diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index a1d1a287e8..7048547b2b 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -55,4 +55,24 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative) BOOST_CHECK(result == false); } +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) +{ + SetWalletDir(m_walletdir_path_cases["trailing"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); + BOOST_CHECK(walletdir == expected_path); +} + +BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2) +{ + SetWalletDir(m_walletdir_path_cases["trailing2"]); + bool result = g_wallet_init_interface.Verify(); + BOOST_CHECK(result == true); + fs::path walletdir = gArgs.GetArg("-walletdir", ""); + fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); + BOOST_CHECK(walletdir == expected_path); +} + BOOST_AUTO_TEST_SUITE_END() From 92af71cea92f8a5185b44e63684b87da9d7ad8a8 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 25 Dec 2014 11:43:52 +0000 Subject: [PATCH 012/263] configure: Make it possible to build only one of bitcoin-cli or bitcoin-tx --- configure.ac | 32 ++++++++++++++----- doc/man/Makefile.am | 8 +++-- src/Makefile.am | 7 ++-- test/config.ini.in | 2 +- .../test_framework/test_framework.py | 2 +- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 4d84aacce1..72bd785e2e 100644 --- a/configure.ac +++ b/configure.ac @@ -406,6 +406,18 @@ AC_ARG_WITH([utils], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) +AC_ARG_ENABLE([util-cli], + [AS_HELP_STRING([--enable-util-cli], + [build bitcoin-cli])], + [build_bitcoin_cli=$enableval], + [build_bitcoin_cli=$build_bitcoin_utils]) + +AC_ARG_ENABLE([util-tx], + [AS_HELP_STRING([--enable-util-tx], + [build bitcoin-tx])], + [build_bitcoin_tx=$enableval], + [build_bitcoin_tx=$build_bitcoin_utils]) + AC_ARG_WITH([libs], [AS_HELP_STRING([--with-libs], [build libraries (default=yes)])], @@ -886,7 +898,7 @@ BITCOIN_QT_INIT dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus BITCOIN_QT_CONFIGURE([$use_pkgconfig]) -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then +if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then use_boost=no else use_boost=yes @@ -1074,7 +1086,7 @@ if test x$use_pkgconfig = xyes; then if test x$use_qr != xno; then BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) fi - if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then + if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests != xnonononono; then PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)]) if test x$TARGET_OS != xwindows; then PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads],, [AC_MSG_ERROR(libevent_pthreads not found.)]) @@ -1099,7 +1111,7 @@ else AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),) AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing)) - if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then + if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests != xnonononono; then AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),) AC_CHECK_LIB([event],[main],EVENT_LIBS=-levent,AC_MSG_ERROR(libevent missing)) if test x$TARGET_OS != xwindows; then @@ -1164,7 +1176,7 @@ dnl univalue check need_bundled_univalue=yes -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then +if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then need_bundled_univalue=no else @@ -1214,9 +1226,13 @@ AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx)]) -AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) -AC_MSG_RESULT($build_bitcoin_utils) +AC_MSG_CHECKING([whether to build bitcoin-cli]) +AM_CONDITIONAL([BUILD_BITCOIN_CLI], [test x$build_bitcoin_cli = xyes]) +AC_MSG_RESULT($build_bitcoin_cli) + +AC_MSG_CHECKING([whether to build bitcoin-tx]) +AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes]) +AC_MSG_RESULT($build_bitcoin_tx) AC_MSG_CHECKING([whether to build libraries]) AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes]) @@ -1342,7 +1358,7 @@ else AC_MSG_RESULT([no]) fi -if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononono; then +if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnonononononono; then AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests]) fi diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 08ff4d6ac1..9b36319e64 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -8,6 +8,10 @@ if ENABLE_QT dist_man1_MANS+=bitcoin-qt.1 endif -if BUILD_BITCOIN_UTILS - dist_man1_MANS+=bitcoin-cli.1 bitcoin-tx.1 +if BUILD_BITCOIN_CLI + dist_man1_MANS+=bitcoin-cli.1 +endif + +if BUILD_BITCOIN_TX + dist_man1_MANS+=bitcoin-tx.1 endif diff --git a/src/Makefile.am b/src/Makefile.am index 159812e847..d036085642 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,8 +83,11 @@ if BUILD_BITCOIND bin_PROGRAMS += bitcoind endif -if BUILD_BITCOIN_UTILS - bin_PROGRAMS += bitcoin-cli bitcoin-tx +if BUILD_BITCOIN_CLI + bin_PROGRAMS += bitcoin-cli +endif +if BUILD_BITCOIN_TX + bin_PROGRAMS += bitcoin-tx endif .PHONY: FORCE check-symbols check-security diff --git a/test/config.ini.in b/test/config.ini.in index a1119dc739..28abee2a3d 100644 --- a/test/config.ini.in +++ b/test/config.ini.in @@ -14,6 +14,6 @@ RPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py [components] # Which components are enabled. These are commented out by `configure` if they were disabled when running config. @ENABLE_WALLET_TRUE@ENABLE_WALLET=true -@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true +@BUILD_BITCOIN_CLI_TRUE@ENABLE_CLI=true @BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true @ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 57c985b2a2..7d4e50c663 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -525,7 +525,7 @@ def is_cli_compiled(self): config = configparser.ConfigParser() config.read_file(open(self.options.configfile)) - return config["components"].getboolean("ENABLE_UTILS") + return config["components"].getboolean("ENABLE_CLI") def is_wallet_compiled(self): """Checks whether the wallet module was compiled.""" From a2a04a5abb347d52b3ef473f7c80c3c0ffc67a2f Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 23 Jan 2018 03:53:26 +0000 Subject: [PATCH 013/263] Bugfix: Only run bitcoin-tx tests when bitcoin-tx is enabled --- src/Makefile.test.include | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index c4ee5f5fcc..90b977f093 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -174,8 +174,10 @@ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: $(BITCOIN_TESTS:.cpp=.cpp.test) +if BUILD_BITCOIN_TX @echo "Running test/util/bitcoin-util-test.py..." $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py +endif @echo "Running test/util/rpcauth-test.py..." $(PYTHON) $(top_builddir)/test/util/rpcauth-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check From 3ccfa34b32b7ed9d7bef05baa36827b4b262197e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 13 Sep 2018 10:36:41 -0700 Subject: [PATCH 014/263] convert C-style (void) parameter lists to C++ style () --- src/httprpc.cpp | 4 ++-- src/httpserver.cpp | 2 +- src/httpserver.h | 4 ++-- src/init.cpp | 2 +- src/key.h | 6 +++--- src/qt/bitcoin.cpp | 2 +- src/qt/macnotificationhandler.h | 2 +- src/qt/rpcconsole.cpp | 6 +++--- src/rpc/server.cpp | 2 +- src/rpc/server.h | 4 ++-- src/scheduler.cpp | 4 ++-- src/scheduler.h | 6 +++--- src/test/crypto_tests.cpp | 2 +- src/util.cpp | 2 +- src/util.h | 2 +- src/validation.cpp | 4 ++-- 16 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 43d8c4cbbf..4064251c71 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -31,7 +31,7 @@ static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\""; class HTTPRPCTimer : public RPCTimerBase { public: - HTTPRPCTimer(struct event_base* eventBase, std::function& func, int64_t millis) : + HTTPRPCTimer(struct event_base* eventBase, std::function& func, int64_t millis) : ev(eventBase, false, func) { struct timeval tv; @@ -53,7 +53,7 @@ class HTTPRPCTimerInterface : public RPCTimerInterface { return "HTTP"; } - RPCTimerBase* NewTimer(std::function& func, int64_t millis) override + RPCTimerBase* NewTimer(std::function& func, int64_t millis) override { return new HTTPRPCTimer(base, func, millis); } diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 326f7f6b64..e176746207 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -505,7 +505,7 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data) delete self; } -HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function& _handler): +HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function& _handler): deleteWhenTriggered(_deleteWhenTriggered), handler(_handler) { ev = event_new(base, -1, 0, httpevent_callback_fn, this); diff --git a/src/httpserver.h b/src/httpserver.h index 67c6a88314..63f96734f8 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -134,7 +134,7 @@ class HTTPEvent * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called) * handler is the handler to call when the event is triggered. */ - HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function& handler); + HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function& handler); ~HTTPEvent(); /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after @@ -143,7 +143,7 @@ class HTTPEvent void trigger(struct timeval* tv); bool deleteWhenTriggered; - std::function handler; + std::function handler; private: struct event* ev; }; diff --git a/src/init.cpp b/src/init.cpp index 45689f7ecd..326e71c8bb 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -684,7 +684,7 @@ static void ThreadImport(std::vector vImportFiles) * Ensure that Bitcoin is running in a usable environment with all * necessary library support. */ -static bool InitSanityCheck(void) +static bool InitSanityCheck() { if(!ECC_InitSanityCheck()) { InitError("Elliptic curve cryptography sanity check failure. Aborting."); diff --git a/src/key.h b/src/key.h index a3baa421e6..0f695c07b7 100644 --- a/src/key.h +++ b/src/key.h @@ -181,12 +181,12 @@ struct CExtKey { }; /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ -void ECC_Start(void); +void ECC_Start(); /** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called first. */ -void ECC_Stop(void); +void ECC_Stop(); /** Check that required EC support is available at runtime. */ -bool ECC_InitSanityCheck(void); +bool ECC_InitSanityCheck(); #endif // BITCOIN_KEY_H diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 87282a961f..1e950e2686 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -586,7 +586,7 @@ int main(int argc, char *argv[]) // Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType) // IMPORTANT if it is no longer a typedef use the normal variant above qRegisterMetaType< CAmount >("CAmount"); - qRegisterMetaType< std::function >("std::function"); + qRegisterMetaType< std::function >("std::function"); #ifdef ENABLE_WALLET qRegisterMetaType("WalletModel*"); #endif diff --git a/src/qt/macnotificationhandler.h b/src/qt/macnotificationhandler.h index 23993adc2e..03c744c12e 100644 --- a/src/qt/macnotificationhandler.h +++ b/src/qt/macnotificationhandler.h @@ -19,7 +19,7 @@ class MacNotificationHandler : public QObject void showNotification(const QString &title, const QString &text); /** check if OS can handle UserNotifications */ - bool hasUserNotificationCenterSupport(void); + bool hasUserNotificationCenterSupport(); static MacNotificationHandler *instance(); }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ad13b20ebe..3857befdf2 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -101,7 +101,7 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase { Q_OBJECT public: - QtRPCTimerBase(std::function& _func, int64_t millis): + QtRPCTimerBase(std::function& _func, int64_t millis): func(_func) { timer.setSingleShot(true); @@ -111,7 +111,7 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase ~QtRPCTimerBase() {} private: QTimer timer; - std::function func; + std::function func; }; class QtRPCTimerInterface: public RPCTimerInterface @@ -119,7 +119,7 @@ class QtRPCTimerInterface: public RPCTimerInterface public: ~QtRPCTimerInterface() {} const char *Name() { return "Qt"; } - RPCTimerBase* NewTimer(std::function& func, int64_t millis) + RPCTimerBase* NewTimer(std::function& func, int64_t millis) { return new QtRPCTimerBase(func, millis); } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 8f3fe31ce8..9eb55880b3 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -540,7 +540,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface) timerInterface = nullptr; } -void RPCRunLater(const std::string& name, std::function func, int64_t nSeconds) +void RPCRunLater(const std::string& name, std::function func, int64_t nSeconds) { if (!timerInterface) throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); diff --git a/src/rpc/server.h b/src/rpc/server.h index 15d0ec80f5..2d62a76f3c 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -110,7 +110,7 @@ class RPCTimerInterface * This is needed to cope with the case in which there is no HTTP server, but * only GUI RPC console, and to break the dependency of pcserver on httprpc. */ - virtual RPCTimerBase* NewTimer(std::function& func, int64_t millis) = 0; + virtual RPCTimerBase* NewTimer(std::function& func, int64_t millis) = 0; }; /** Set the factory function for timers */ @@ -124,7 +124,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface); * Run func nSeconds from now. * Overrides previous timer (if any). */ -void RPCRunLater(const std::string& name, std::function func, int64_t nSeconds); +void RPCRunLater(const std::string& name, std::function func, int64_t nSeconds); typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 89dfc2b363..552391d7d0 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -159,7 +159,7 @@ void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() { } void SingleThreadedSchedulerClient::ProcessQueue() { - std::function callback; + std::function callback; { LOCK(m_cs_callbacks_pending); if (m_are_callbacks_running) return; @@ -187,7 +187,7 @@ void SingleThreadedSchedulerClient::ProcessQueue() { callback(); } -void SingleThreadedSchedulerClient::AddToProcessQueue(std::function func) { +void SingleThreadedSchedulerClient::AddToProcessQueue(std::function func) { assert(m_pscheduler); { diff --git a/src/scheduler.h b/src/scheduler.h index 953d6c37de..6c45f508ec 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -40,7 +40,7 @@ class CScheduler CScheduler(); ~CScheduler(); - typedef std::function Function; + typedef std::function Function; // Call func at/after time t void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now()); @@ -99,7 +99,7 @@ class SingleThreadedSchedulerClient { CScheduler *m_pscheduler; CCriticalSection m_cs_callbacks_pending; - std::list> m_callbacks_pending GUARDED_BY(m_cs_callbacks_pending); + std::list> m_callbacks_pending GUARDED_BY(m_cs_callbacks_pending); bool m_are_callbacks_running GUARDED_BY(m_cs_callbacks_pending) = false; void MaybeScheduleProcessQueue(); @@ -114,7 +114,7 @@ class SingleThreadedSchedulerClient { * Practically, this means that callbacks can behave as if they are executed * in order by a single thread. */ - void AddToProcessQueue(std::function func); + void AddToProcessQueue(std::function func); // Processes all remaining queue members on the calling thread, blocking until queue is empty // Must be called after the CScheduler has no remaining processing threads! diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 19521027a9..713e3e2ded 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -200,7 +200,7 @@ static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t see BOOST_CHECK(out == outres); } -static std::string LongTestString(void) { +static std::string LongTestString() { std::string ret; for (int i=0; i<200000; i++) { ret += (unsigned char)(i); diff --git a/src/util.cpp b/src/util.cpp index ee8bc94584..75a387d7ec 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1248,7 +1248,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific) return fs::absolute(path, GetDataDir(net_specific)); } -int ScheduleBatchPriority(void) +int ScheduleBatchPriority() { #ifdef SCHED_BATCH const static sched_param param{0}; diff --git a/src/util.h b/src/util.h index 7bf9fdbe12..f119385e48 100644 --- a/src/util.h +++ b/src/util.h @@ -347,7 +347,7 @@ std::string CopyrightHolders(const std::string& strPrefix); * @return The return value of sched_setschedule(), or 1 on systems without * sched_setschedule(). */ -int ScheduleBatchPriority(void); +int ScheduleBatchPriority(); namespace util { diff --git a/src/validation.cpp b/src/validation.cpp index 947192be0e..cb617ae6a5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4682,7 +4682,7 @@ int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::D static const uint64_t MEMPOOL_DUMP_VERSION = 1; -bool LoadMempool(void) +bool LoadMempool() { const CChainParams& chainparams = Params(); int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60; @@ -4759,7 +4759,7 @@ bool LoadMempool(void) return true; } -bool DumpMempool(void) +bool DumpMempool() { int64_t start = GetTimeMicros(); From be54f42e5f309ff332d74828ae294636d77fb8ea Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 15 Sep 2018 12:45:41 -0700 Subject: [PATCH 015/263] use integer division instead of double conversion and multiplication for computing amounts --- src/validation.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation.h b/src/validation.h index 3df6456eca..1034ba4665 100644 --- a/src/validation.h +++ b/src/validation.h @@ -53,9 +53,9 @@ static const bool DEFAULT_WHITELISTFORCERELAY = true; /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; //! -maxtxfee default -static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN; +static const CAmount DEFAULT_TRANSACTION_MAXFEE = COIN / 10; //! Discourage users to set fees higher than this amount (in satoshis) per kB -static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN; +static const CAmount HIGH_TX_FEE_PER_KB = COIN / 100; //! -maxtxfee will warn if called with a higher fee than this amount (in satoshis) static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB; /** Default for -limitancestorcount, max number of in-mempool ancestors */ From 2148c36b6ec02fcf10d6d3b76e50b690ee93bdfd Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Mon, 20 Aug 2018 02:54:54 +0800 Subject: [PATCH 016/263] tests: Make it possible to run functional tests on Windows --- test/functional/combine_logs.py | 4 --- test/functional/feature_block.py | 2 +- test/functional/test_framework/authproxy.py | 26 +++++++++------ test/functional/test_runner.py | 36 +++++++++++++++++---- test/functional/wallet_multiwallet.py | 17 ++++++---- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py index 3759913e44..3230d5cb6b 100755 --- a/test/functional/combine_logs.py +++ b/test/functional/combine_logs.py @@ -25,10 +25,6 @@ def main(): parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2') args, unknown_args = parser.parse_known_args() - if args.color and os.name != 'posix': - print("Color output requires posix terminal colors.") - sys.exit(1) - if args.html and args.color: print("Only one out of --color or --html should be specified") sys.exit(1) diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 6e36ea5601..8218abf455 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -827,7 +827,7 @@ def run_test(self): tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0))) b64a = self.update_block("64a", [tx]) assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8) - self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize(): iostream error') + self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize():') # bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently # resend the header message, it won't send us the getdata message again. Just diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py index 900090bb66..1140fe9b3e 100644 --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -38,6 +38,7 @@ import http.client import json import logging +import os import socket import time import urllib.parse @@ -71,19 +72,12 @@ def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connect self._service_name = service_name self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests self.__url = urllib.parse.urlparse(service_url) - port = 80 if self.__url.port is None else self.__url.port user = None if self.__url.username is None else self.__url.username.encode('utf8') passwd = None if self.__url.password is None else self.__url.password.encode('utf8') authpair = user + b':' + passwd self.__auth_header = b'Basic ' + base64.b64encode(authpair) - - if connection: - # Callables re-use the connection of the original proxy - self.__conn = connection - elif self.__url.scheme == 'https': - self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=timeout) - else: - self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=timeout) + self.timeout = timeout + self._set_conn(connection) def __getattr__(self, name): if name.startswith('__') and name.endswith('__'): @@ -102,6 +96,10 @@ def _request(self, method, path, postdata): 'User-Agent': USER_AGENT, 'Authorization': self.__auth_header, 'Content-type': 'application/json'} + if os.name == 'nt': + # Windows somehow does not like to re-use connections + # TODO: Find out why the connection would disconnect occasionally and make it reusable on Windows + self._set_conn() try: self.__conn.request(method, path, postdata, headers) return self._get_response() @@ -178,3 +176,13 @@ def _get_response(self): def __truediv__(self, relative_uri): return AuthServiceProxy("{}/{}".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn) + + def _set_conn(self, connection=None): + port = 80 if self.__url.port is None else self.__url.port + if connection: + self.__conn = connection + self.timeout = connection.timeout + elif self.__url.scheme == 'https': + self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=self.timeout) + else: + self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=self.timeout) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 37a3c1c602..28437f8925 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -29,7 +29,7 @@ import logging # Formatting. Default colors to empty strings. -BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "") +BOLD, GREEN, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "") try: # Make sure python thinks it can write unicode to its stdout "\u2713".encode("utf_8").decode(sys.stdout.encoding) @@ -41,11 +41,27 @@ CROSS = "x " CIRCLE = "o " -if os.name == 'posix': +if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393): + if os.name == 'nt': + import ctypes + kernel32 = ctypes.windll.kernel32 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 + STD_OUTPUT_HANDLE = -11 + STD_ERROR_HANDLE = -12 + # Enable ascii color control to stdout + stdout = kernel32.GetStdHandle(STD_OUTPUT_HANDLE) + stdout_mode = ctypes.c_int32() + kernel32.GetConsoleMode(stdout, ctypes.byref(stdout_mode)) + kernel32.SetConsoleMode(stdout, stdout_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING) + # Enable ascii color control to stderr + stderr = kernel32.GetStdHandle(STD_ERROR_HANDLE) + stderr_mode = ctypes.c_int32() + kernel32.GetConsoleMode(stderr, ctypes.byref(stderr_mode)) + kernel32.SetConsoleMode(stderr, stderr_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING) # primitive formatting on supported # terminal via ANSI escape sequences: BOLD = ('\033[0m', '\033[1m') - BLUE = ('\033[0m', '\033[0;34m') + GREEN = ('\033[0m', '\033[0;32m') RED = ('\033[0m', '\033[0;31m') GREY = ('\033[0m', '\033[1;30m') @@ -227,6 +243,11 @@ def main(): # Create base test directory tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) + + # If we fixed the command-line and filename encoding issue on Windows, these two lines could be removed + if config["environment"]["EXEEXT"] == ".exe": + tmpdir = "%s/test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S")) + os.makedirs(tmpdir) logging.debug("Temporary test directory at %s" % tmpdir) @@ -264,7 +285,7 @@ def main(): # Remove the test cases that the user has explicitly asked to exclude. if args.exclude: - exclude_tests = [re.sub("\.py$", "", test) + ".py" for test in args.exclude.split(',')] + exclude_tests = [re.sub("\.py$", "", test) + (".py" if ".py" not in test else "") for test in args.exclude.split(',')] for exclude_test in exclude_tests: if exclude_test in test_list: test_list.remove(exclude_test) @@ -359,7 +380,10 @@ def run_tests(test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=Fal print('\n============') print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0])) print('============\n') - combined_logs, _ = subprocess.Popen([sys.executable, os.path.join(tests_dir, 'combine_logs.py'), '-c', testdir], universal_newlines=True, stdout=subprocess.PIPE).communicate() + combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir] + if BOLD[0]: + combined_logs_args += ['--color'] + combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate() print("\n".join(deque(combined_logs.splitlines(), combined_logs_len))) if failfast: @@ -498,7 +522,7 @@ def sort_key(self): def __repr__(self): if self.status == "Passed": - color = BLUE + color = GREEN glyph = TICK elif self.status == "Failed": color = RED diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 435821ec48..189bc2d50e 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -44,8 +44,9 @@ def wallet_file(name): # create symlink to verify wallet directory path can be referenced # through symlink - os.mkdir(wallet_dir('w7')) - os.symlink('w7', wallet_dir('w7_symlink')) + if os.name != 'nt': + os.mkdir(wallet_dir('w7')) + os.symlink('w7', wallet_dir('w7_symlink')) # rename wallet.dat to make sure plain wallet file paths (as opposed to # directory paths) can be loaded @@ -66,6 +67,8 @@ def wallet_file(name): # w8 - to verify existing wallet file is loaded correctly # '' - to verify default wallet file is created correctly wallet_names = ['w1', 'w2', 'w3', 'w', 'sub/w5', os.path.join(self.options.tmpdir, 'extern/w6'), 'w7_symlink', 'w8', ''] + if os.name == 'nt': + wallet_names.remove('w7_symlink') extra_args = ['-wallet={}'.format(n) for n in wallet_names] self.start_node(0, extra_args) assert_equal(set(node.listwallets()), set(wallet_names)) @@ -76,7 +79,7 @@ def wallet_file(name): assert_equal(os.path.isfile(wallet_file(wallet_name)), True) # should not initialize if wallet path can't be created - exp_stderr = "boost::filesystem::create_directory: (The system cannot find the path specified|Not a directory):" + exp_stderr = "boost::filesystem::create_directory:" self.nodes[0].assert_start_raises_init_error(['-wallet=wallet.dat/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX) self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist') @@ -92,8 +95,9 @@ def wallet_file(name): self.nodes[0].assert_start_raises_init_error(['-wallet=w8', '-wallet=w8_copy'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX) # should not initialize if wallet file is a symlink - os.symlink('w8', wallet_dir('w8_symlink')) - self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Error: Invalid -wallet path \'w8_symlink\'\. .*', match=ErrorMatch.FULL_REGEX) + if os.name != 'nt': + os.symlink('w8', wallet_dir('w8_symlink')) + self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Error: Invalid -wallet path \'w8_symlink\'\. .*', match=ErrorMatch.FULL_REGEX) # should not initialize if the specified walletdir does not exist self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist') @@ -220,7 +224,8 @@ def wallet_file(name): assert_raises_rpc_error(-1, "BerkeleyBatch: Can't open database w8_copy (duplicates fileid", self.nodes[0].loadwallet, 'w8_copy') # Fail to load if wallet file is a symlink - assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink') + if os.name != 'nt': + assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink') # Fail to load if a directory is specified that doesn't contain a wallet os.mkdir(wallet_dir('empty_wallet_dir')) From 0ca4c8b3c61984e9e2ab5a2a9a7c47faf139d1fc Mon Sep 17 00:00:00 2001 From: sanket1729 Date: Sat, 15 Sep 2018 04:32:12 -0500 Subject: [PATCH 017/263] Changed functional tests which do not require wallets to run without skipping .Addreses #14216. Changed get_deterministic_priv_key() to a named tuple --- test/functional/example_test.py | 2 ++ test/functional/feature_block.py | 3 --- test/functional/feature_blocksdir.py | 5 +---- test/functional/feature_logging.py | 3 --- test/functional/feature_minchainwork.py | 8 +++----- test/functional/feature_reindex.py | 5 +---- .../functional/feature_versionbits_warning.py | 16 +++++++-------- test/functional/mining_basic.py | 7 ++----- test/functional/p2p_fingerprint.py | 7 ++----- test/functional/p2p_invalid_block.py | 5 +---- test/functional/p2p_invalid_locator.py | 5 +---- test/functional/p2p_invalid_tx.py | 5 +---- test/functional/p2p_leak.py | 5 +---- test/functional/p2p_node_network_limited.py | 7 ++----- test/functional/p2p_sendheaders.py | 12 +++++------ test/functional/p2p_unrequested_blocks.py | 7 ++----- test/functional/rpc_blockchain.py | 7 ++----- test/functional/rpc_getchaintips.py | 7 ++----- test/functional/rpc_invalidateblock.py | 9 +++------ test/functional/rpc_preciousblock.py | 16 +++++++-------- .../test_framework/test_framework.py | 4 ++-- test/functional/test_framework/test_node.py | 20 ++++++++++--------- 22 files changed, 58 insertions(+), 107 deletions(-) diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 937a525401..3f15367a75 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -85,6 +85,8 @@ def set_test_params(self): # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() + # Use skip_test_if_missing_module() to skip the test if your test requires certain modules to be present. + # This test uses generate which requires wallet to be compiled def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 6e36ea5601..71c3a396c1 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -75,9 +75,6 @@ def set_test_params(self): self.setup_clean_chain = True self.extra_args = [[]] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): node = self.nodes[0] # convenience reference to the node diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py index 824f0d7e09..c170f510c8 100755 --- a/test/functional/feature_blocksdir.py +++ b/test/functional/feature_blocksdir.py @@ -16,9 +16,6 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): self.stop_node(0) shutil.rmtree(self.nodes[0].datadir) @@ -30,7 +27,7 @@ def run_test(self): self.log.info("Starting with existing blocksdir ...") self.start_node(0, ["-blocksdir=" + blocksdir_path]) self.log.info("mining blocks..") - self.nodes[0].generate(10) + self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address) assert os.path.isfile(os.path.join(blocksdir_path, "regtest", "blocks", "blk00000.dat")) assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest", "blocks", "index")) diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py index a74c413440..8bb7e02695 100755 --- a/test/functional/feature_logging.py +++ b/test/functional/feature_logging.py @@ -15,9 +15,6 @@ def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def relative_log_path(self, name): return os.path.join(self.nodes[0].datadir, "regtest", name) diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py index 5d180c2244..dbff6f15f2 100755 --- a/test/functional/feature_minchainwork.py +++ b/test/functional/feature_minchainwork.py @@ -31,9 +31,6 @@ def set_test_params(self): self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]] self.node_min_work = [0, 101, 101] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): # This test relies on the chain setup being: # node0 <- node1 <- node2 @@ -54,7 +51,8 @@ def run_test(self): num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK) self.log.info("Generating %d blocks on node0", num_blocks_to_generate) - hashes = self.nodes[0].generate(num_blocks_to_generate) + hashes = self.nodes[0].generatetoaddress(num_blocks_to_generate, + self.nodes[0].get_deterministic_priv_key().address) self.log.info("Node0 current chain work: %s", self.nodes[0].getblockheader(hashes[-1])['chainwork']) @@ -75,7 +73,7 @@ def run_test(self): assert_equal(self.nodes[2].getblockcount(), starting_blockcount) self.log.info("Generating one more block") - self.nodes[0].generate(1) + self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address) self.log.info("Verifying nodes are all synced") diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py index 3727eeaeae..940b403f9c 100755 --- a/test/functional/feature_reindex.py +++ b/test/functional/feature_reindex.py @@ -18,11 +18,8 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def reindex(self, justchainstate=False): - self.nodes[0].generate(3) + self.nodes[0].generatetoaddress(3, self.nodes[0].get_deterministic_priv_key().address) blockcount = self.nodes[0].getblockcount() self.stop_nodes() extra_args = [["-reindex-chainstate" if justchainstate else "-reindex"]] diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index cf77720437..88df61cabc 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -31,9 +31,6 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") # Open and close to create zero-length file @@ -68,13 +65,14 @@ def run_test(self): node = self.nodes[0] node.add_p2p_connection(P2PInterface()) + node_deterministic_address = node.get_deterministic_priv_key().address # Mine one period worth of blocks - node.generate(VB_PERIOD) + node.generatetoaddress(VB_PERIOD, node_deterministic_address) self.log.info("Check that there is no warning if previous VB_BLOCKS have 50 blocks in the last 100 were an unknown version") # Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION) - node.generate(VB_PERIOD - VB_THRESHOLD) + node.generatetoaddress(VB_PERIOD - VB_THRESHOLD, node_deterministic_address) # Check that get*info() shows the 51/100 unknown block version error. assert(WARN_UNKNOWN_RULES_MINED in node.getmininginfo()["warnings"]) @@ -92,16 +90,16 @@ def run_test(self): self.log.info("Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version.") # Mine a period worth of expected blocks so the generic block-version warning # is cleared. This will move the versionbit state to ACTIVE. - node.generate(VB_PERIOD) + node.generatetoaddress(VB_PERIOD, node_deterministic_address) # Stop-start the node. This is required because bitcoind will only warn once about unknown versions or unknown rules activating. self.restart_node(0) # Generating one block guarantees that we'll get out of IBD - node.generate(1) + node.generatetoaddress(1, node_deterministic_address) wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock) # Generating one more block will be enough to generate an error. - node.generate(1) + node.generatetoaddress(1, node_deterministic_address) # Check that get*info() shows the versionbits unknown rules warning assert(WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()["warnings"]) assert(WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()["warnings"]) diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index f95ad31e7c..ff55ea5528 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -38,9 +38,6 @@ def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = False - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): node = self.nodes[0] @@ -61,7 +58,7 @@ def assert_submitblock(block, result_str_1, result_str_2=None): assert_equal(mining_info['pooledtx'], 0) # Mine a block to leave initial block download - node.generate(1) + node.generatetoaddress(1, node.get_deterministic_priv_key().address) tmpl = node.getblocktemplate() self.log.info("getblocktemplate: Test capability advertised") assert 'proposal' in tmpl['capabilities'] @@ -212,7 +209,7 @@ def chain_tip(b_hash, *, status='headers-only', branchlen=1): assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips() # Building a few blocks should give the same results - node.generate(10) + node.generatetoaddress(10, node.get_deterministic_priv_key().address) assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize()))) assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize()))) node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index 884fb4b063..fab0887197 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -30,9 +30,6 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - # Build a chain of blocks on top of given one def build_chain(self, nblocks, prev_hash, prev_height, prev_median_time): blocks = [] @@ -83,7 +80,7 @@ def run_test(self): self.nodes[0].setmocktime(int(time.time()) - 60 * 24 * 60 * 60) # Generating a chain of 10 blocks - block_hashes = self.nodes[0].generate(nblocks=10) + block_hashes = self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address) # Create longer chain starting 2 blocks before current tip height = len(block_hashes) - 2 @@ -114,7 +111,7 @@ def run_test(self): # Longest chain is extended so stale is much older than chain tip self.nodes[0].setmocktime(0) - tip = self.nodes[0].generate(nblocks=1)[0] + tip = self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0] assert_equal(self.nodes[0].getblockcount(), 14) # Send getdata & getheaders to refresh last received getheader message diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index fd6b84f8b2..7be7c9b3ee 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -24,9 +24,6 @@ def set_test_params(self): self.setup_clean_chain = True self.extra_args = [["-whitelist=127.0.0.1"]] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): # Add p2p connection to node0 node = self.nodes[0] # convenience reference to the node @@ -48,7 +45,7 @@ def run_test(self): node.p2p.send_blocks_and_test([block1], node, success=True) self.log.info("Mature the block.") - node.generate(100) + node.generatetoaddress(100, node.get_deterministic_priv_key().address) best_block = node.getblock(node.getbestblockhash()) tip = int(node.getbestblockhash(), 16) diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index 4cc43a4fa4..c8c752d1f7 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -15,12 +15,9 @@ def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = False - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): node = self.nodes[0] # convenience reference to the node - node.generate(1) # Get node out of IBD + node.generatetoaddress(1, node.get_deterministic_priv_key().address) # Get node out of IBD self.log.info('Test max locator size') block_count = node.getblockcount() diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index 2f19b4d933..58e129b57d 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -26,9 +26,6 @@ def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def bootstrap_p2p(self, *, num_connections=1): """Add a P2P connection to the node. @@ -64,7 +61,7 @@ def run_test(self): node.p2p.send_blocks_and_test([block], node, success=True) self.log.info("Mature the block.") - self.nodes[0].generate(100) + self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address) # b'\x64' is OP_NOTIF # Transaction will be rejected with code 16 (REJECT_INVALID) diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 05354d17e1..336d34a81d 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -93,9 +93,6 @@ def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-banscore=' + str(banscore)]] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False) no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False) @@ -106,7 +103,7 @@ def run_test(self): wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock) # Mine a block and make sure that it's not sent to the connected nodes - self.nodes[0].generate(1) + self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address) #Give the node enough time to possibly leak out a message time.sleep(5) diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index a16c6a1d47..ec3d336dc1 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -34,9 +34,6 @@ def set_test_params(self): self.num_nodes = 3 self.extra_args = [['-prune=550', '-addrmantest'], [], []] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def disconnect_all(self): disconnect_nodes(self.nodes[0], 1) disconnect_nodes(self.nodes[1], 0) @@ -62,7 +59,7 @@ def run_test(self): self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.") connect_nodes_bi(self.nodes, 0, 1) - blocks = self.nodes[1].generate(292) + blocks = self.nodes[1].generatetoaddress(292, self.nodes[1].get_deterministic_priv_key().address) sync_blocks([self.nodes[0], self.nodes[1]]) self.log.info("Make sure we can max retrieve block at tip-288.") @@ -105,7 +102,7 @@ def run_test(self): self.disconnect_all() # mine 10 blocks on node 0 (pruned node) - self.nodes[0].generate(10) + self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address) # connect node1 (non pruned) with node0 (pruned) and check if the can sync connect_nodes_bi(self.nodes, 0, 1) diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index 9a782c0bb9..d5e8dd4721 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -208,15 +208,12 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def mine_blocks(self, count): """Mine count blocks and return the new tip.""" # Clear out block announcements from each p2p listener [x.clear_block_announcements() for x in self.nodes[0].p2ps] - self.nodes[0].generate(count) + self.nodes[0].generatetoaddress(count, self.nodes[0].get_deterministic_priv_key().address) return int(self.nodes[0].getbestblockhash(), 16) def mine_reorg(self, length): @@ -226,7 +223,8 @@ def mine_reorg(self, length): to-be-reorged-out blocks are mined, so that we don't break later tests. return the list of block hashes newly mined.""" - self.nodes[0].generate(length) # make sure all invalidated blocks are node0's + # make sure all invalidated blocks are node0's + self.nodes[0].generatetoaddress(length, self.nodes[0].get_deterministic_priv_key().address) sync_blocks(self.nodes, wait=0.1) for x in self.nodes[0].p2ps: x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16)) @@ -235,7 +233,7 @@ def mine_reorg(self, length): tip_height = self.nodes[1].getblockcount() hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1)) self.nodes[1].invalidateblock(hash_to_invalidate) - all_hashes = self.nodes[1].generate(length + 1) # Must be longer than the orig chain + all_hashes = self.nodes[1].generatetoaddress(length + 1, self.nodes[1].get_deterministic_priv_key().address) # Must be longer than the orig chain sync_blocks(self.nodes, wait=0.1) return [int(x, 16) for x in all_hashes] @@ -254,7 +252,7 @@ def run_test(self): self.test_nonnull_locators(test_node, inv_node) def test_null_locators(self, test_node, inv_node): - tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0]) + tip = self.nodes[0].getblockheader(self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)[0]) tip_hash = int(tip["hash"], 16) inv_node.check_last_inv_announcement(inv=[tip_hash]) diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 232274f59e..11299cbc00 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -66,9 +66,6 @@ def set_test_params(self): self.num_nodes = 2 self.extra_args = [[], ["-minimumchainwork=0x10"]] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): # Node0 will be used to test behavior of processing unrequested blocks # from peers which are not whitelisted, while Node1 will be used for @@ -85,8 +82,8 @@ def run_test(self): min_work_node = self.nodes[1].add_p2p_connection(P2PInterface()) # 1. Have nodes mine a block (leave IBD) - [ n.generate(1) for n in self.nodes ] - tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ] + [n.generatetoaddress(1, n.get_deterministic_priv_key().address) for n in self.nodes] + tips = [int("0x" + n.getbestblockhash(), 0) for n in self.nodes] # 2. Send one block that builds on each tip. # This should be accepted by node0 diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 00317a2c08..f67ecc247c 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -48,9 +48,6 @@ class BlockchainTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete @@ -242,12 +239,12 @@ def _test_getnetworkhashps(self): def _test_stopatheight(self): assert_equal(self.nodes[0].getblockcount(), 200) - self.nodes[0].generate(6) + self.nodes[0].generatetoaddress(6, self.nodes[0].get_deterministic_priv_key().address) assert_equal(self.nodes[0].getblockcount(), 206) self.log.debug('Node should not stop at this height') assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3)) try: - self.nodes[0].generate(1) + self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address) except (ConnectionError, http.client.BadStatusLine): pass # The node already shut down before response self.log.debug('Node should stop at this height...') diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py index bc19c60dde..c869c7262f 100755 --- a/test/functional/rpc_getchaintips.py +++ b/test/functional/rpc_getchaintips.py @@ -17,9 +17,6 @@ class GetChainTipsTest (BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): tips = self.nodes[0].getchaintips() assert_equal(len(tips), 1) @@ -29,8 +26,8 @@ def run_test(self): # Split the network and build two chains of different lengths. self.split_network() - self.nodes[0].generate(10) - self.nodes[2].generate(20) + self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address) + self.nodes[2].generatetoaddress(20, self.nodes[2].get_deterministic_priv_key().address) self.sync_all([self.nodes[:2], self.nodes[2:]]) tips = self.nodes[1].getchaintips () diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index 84f7cd05fb..d8ecdd573a 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -14,21 +14,18 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): self.setup_nodes() def run_test(self): self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") self.log.info("Mine 4 blocks on Node 0") - self.nodes[0].generate(4) + self.nodes[0].generatetoaddress(4, self.nodes[0].get_deterministic_priv_key().address) assert(self.nodes[0].getblockcount() == 4) besthash = self.nodes[0].getbestblockhash() self.log.info("Mine competing 6 blocks on Node 1") - self.nodes[1].generate(6) + self.nodes[1].generatetoaddress(6, self.nodes[1].get_deterministic_priv_key().address) assert(self.nodes[1].getblockcount() == 6) self.log.info("Connect nodes to force a reorg") @@ -56,7 +53,7 @@ def run_test(self): self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) assert(self.nodes[2].getblockcount() == 2) self.log.info("..and then mine a block") - self.nodes[2].generate(1) + self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address) self.log.info("Verify all nodes are at the right height") time.sleep(5) assert_equal(self.nodes[2].getblockcount(), 3) diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py index f383b82bb5..72e6e6329f 100755 --- a/test/functional/rpc_preciousblock.py +++ b/test/functional/rpc_preciousblock.py @@ -38,26 +38,24 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): self.setup_nodes() def run_test(self): self.log.info("Ensure submitblock can in principle reorg to a competing chain") - self.nodes[0].generate(1) + gen_address = lambda i: self.nodes[i].get_deterministic_priv_key().address # A non-wallet address to mine to + self.nodes[0].generatetoaddress(1, gen_address(0)) assert_equal(self.nodes[0].getblockcount(), 1) - hashZ = self.nodes[1].generate(2)[-1] + hashZ = self.nodes[1].generatetoaddress(2, gen_address(1))[-1] assert_equal(self.nodes[1].getblockcount(), 2) node_sync_via_rpc(self.nodes[0:3]) assert_equal(self.nodes[0].getbestblockhash(), hashZ) self.log.info("Mine blocks A-B-C on Node 0") - hashC = self.nodes[0].generate(3)[-1] + hashC = self.nodes[0].generatetoaddress(3, gen_address(0))[-1] assert_equal(self.nodes[0].getblockcount(), 5) self.log.info("Mine competing blocks E-F-G on Node 1") - hashG = self.nodes[1].generate(3)[-1] + hashG = self.nodes[1].generatetoaddress(3, gen_address(1))[-1] assert_equal(self.nodes[1].getblockcount(), 5) assert(hashC != hashG) self.log.info("Connect nodes and check no reorg occurs") @@ -86,7 +84,7 @@ def run_test(self): self.nodes[1].preciousblock(hashC) assert_equal(self.nodes[1].getbestblockhash(), hashC) self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1") - self.nodes[0].generate(1) + self.nodes[0].generatetoaddress(1, gen_address(0)) assert_equal(self.nodes[0].getblockcount(), 6) sync_blocks(self.nodes[0:2]) hashH = self.nodes[0].getbestblockhash() @@ -95,7 +93,7 @@ def run_test(self): self.nodes[1].preciousblock(hashC) assert_equal(self.nodes[1].getbestblockhash(), hashH) self.log.info("Mine competing blocks I-J-K-L on Node 2") - self.nodes[2].generate(4) + self.nodes[2].generatetoaddress(4, gen_address(2)) assert_equal(self.nodes[2].getblockcount(), 6) hashL = self.nodes[2].getbestblockhash() self.log.info("Connect nodes and check no reorg occurs") diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 57c985b2a2..9a589240a8 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -271,7 +271,7 @@ def import_deterministic_coinbase_privkeys(self): assert str(e).startswith('Method not found') continue - n.importprivkey(n.get_deterministic_priv_key()[1]) + n.importprivkey(n.get_deterministic_priv_key().key) def run_test(self): """Tests must override this method to define test logic""" @@ -465,7 +465,7 @@ def _initialize_chain(self): for peer in range(4): for j in range(25): set_node_times(self.nodes, block_time) - self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key()[0]) + self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key().address) block_time += 10 * 60 # Must sync before next peer starts generating blocks sync_blocks(self.nodes) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index c267f7f24f..7ab7fcfcb4 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -17,6 +17,7 @@ import tempfile import time import urllib.parse +import collections from .authproxy import JSONRPCException from .util import ( @@ -99,17 +100,18 @@ def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, mock def get_deterministic_priv_key(self): """Return a deterministic priv key in base58, that only depends on the node's index""" + AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key']) PRIV_KEYS = [ # address , privkey - ('mjTkW3DjgyZck4KbiRusZsqTgaYTxdSz6z', 'cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW'), - ('msX6jQXvxiNhx3Q62PKeLPrhrqZQdSimTg', 'cUxsWyKyZ9MAQTaAhUQWJmBbSvHMwSmuv59KgxQV7oZQU3PXN3KE'), - ('mnonCMyH9TmAsSj3M59DsbH8H63U3RKoFP', 'cTrh7dkEAeJd6b3MRX9bZK8eRmNqVCMH3LSUkE3dSFDyzjU38QxK'), - ('mqJupas8Dt2uestQDvV2NH3RU8uZh2dqQR', 'cVuKKa7gbehEQvVq717hYcbE9Dqmq7KEBKqWgWrYBa2CKKrhtRim'), - ('msYac7Rvd5ywm6pEmkjyxhbCDKqWsVeYws', 'cQDCBuKcjanpXDpCqacNSjYfxeQj8G6CAtH1Dsk3cXyqLNC4RPuh'), - ('n2rnuUnwLgXqf9kk2kjvVm8R5BZK1yxQBi', 'cQakmfPSLSqKHyMFGwAqKHgWUiofJCagVGhiB4KCainaeCSxeyYq'), - ('myzuPxRwsf3vvGzEuzPfK9Nf2RfwauwYe6', 'cQMpDLJwA8DBe9NcQbdoSb1BhmFxVjWD5gRyrLZCtpuF9Zi3a9RK'), - ('mumwTaMtbxEPUswmLBBN3vM9oGRtGBrys8', 'cSXmRKXVcoouhNNVpcNKFfxsTsToY5pvB9DVsFksF1ENunTzRKsy'), - ('mpV7aGShMkJCZgbW7F6iZgrvuPHjZjH9qg', 'cSoXt6tm3pqy43UMabY6eUTmR3eSUYFtB2iNQDGgb3VUnRsQys2k'), + AddressKeyPair('mjTkW3DjgyZck4KbiRusZsqTgaYTxdSz6z', 'cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW'), + AddressKeyPair('msX6jQXvxiNhx3Q62PKeLPrhrqZQdSimTg', 'cUxsWyKyZ9MAQTaAhUQWJmBbSvHMwSmuv59KgxQV7oZQU3PXN3KE'), + AddressKeyPair('mnonCMyH9TmAsSj3M59DsbH8H63U3RKoFP', 'cTrh7dkEAeJd6b3MRX9bZK8eRmNqVCMH3LSUkE3dSFDyzjU38QxK'), + AddressKeyPair('mqJupas8Dt2uestQDvV2NH3RU8uZh2dqQR', 'cVuKKa7gbehEQvVq717hYcbE9Dqmq7KEBKqWgWrYBa2CKKrhtRim'), + AddressKeyPair('msYac7Rvd5ywm6pEmkjyxhbCDKqWsVeYws', 'cQDCBuKcjanpXDpCqacNSjYfxeQj8G6CAtH1Dsk3cXyqLNC4RPuh'), + AddressKeyPair('n2rnuUnwLgXqf9kk2kjvVm8R5BZK1yxQBi', 'cQakmfPSLSqKHyMFGwAqKHgWUiofJCagVGhiB4KCainaeCSxeyYq'), + AddressKeyPair('myzuPxRwsf3vvGzEuzPfK9Nf2RfwauwYe6', 'cQMpDLJwA8DBe9NcQbdoSb1BhmFxVjWD5gRyrLZCtpuF9Zi3a9RK'), + AddressKeyPair('mumwTaMtbxEPUswmLBBN3vM9oGRtGBrys8', 'cSXmRKXVcoouhNNVpcNKFfxsTsToY5pvB9DVsFksF1ENunTzRKsy'), + AddressKeyPair('mpV7aGShMkJCZgbW7F6iZgrvuPHjZjH9qg', 'cSoXt6tm3pqy43UMabY6eUTmR3eSUYFtB2iNQDGgb3VUnRsQys2k'), ] return PRIV_KEYS[self.index] From 661ac15a4aafae6ec1579721ef36ca2fde9c17b0 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Mon, 27 Aug 2018 17:51:06 +0800 Subject: [PATCH 018/263] appveyor: Run functional tests on appveyor --- appveyor.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 99e7b9510b..c2e1c00b8d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,7 @@ environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true CLCACHE_SERVER: 1 PACKAGES: boost-filesystem boost-signals2 boost-interprocess boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb + PYTHONIOENCODING: utf-8 cache: - C:\tools\vcpkg\installed - C:\Users\appveyor\clcache @@ -15,6 +16,8 @@ init: - cmd: set PATH=C:\Python36-x64;C:\Python36-x64\Scripts;%PATH% install: - cmd: pip install git+https://github.com/frerich/clcache.git +# Disable zmq test for now since python zmq library on Windows would cause Access violation sometimes. +# - cmd: pip install zmq - ps: $packages = $env:PACKAGES -Split ' ' - ps: for ($i=0; $i -lt $packages.length; $i++) { $env:ALL_PACKAGES += $packages[$i] + ":" + $env:PLATFORM + "-windows-static " @@ -40,6 +43,17 @@ after_build: - cmd: move build_msvc\%PLATFORM%\%CONFIGURATION%\*.iobj build_msvc\cache\ - cmd: move build_msvc\%PLATFORM%\%CONFIGURATION%\*.ipdb build_msvc\cache\ - cmd: del C:\Users\appveyor\clcache\stats.txt +before_test: +- ps: ${conf_ini} = (Get-Content([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini.in"))) +- ps: ${conf_ini} = $conf_ini.Replace("@abs_top_srcdir@", ${env:APPVEYOR_BUILD_FOLDER}).Replace("@abs_top_builddir@", ${env:APPVEYOR_BUILD_FOLDER}).Replace("@EXEEXT@", ".exe") +- ps: ${conf_ini} = $conf_ini.Replace("@ENABLE_WALLET_TRUE@", "").Replace("@BUILD_BITCOIN_UTILS_TRUE@", "").Replace("@BUILD_BITCOIND_TRUE@", "").Replace("@ENABLE_ZMQ_TRUE@", "") +- ps: ${utf8} = New-Object System.Text.UTF8Encoding ${false} +- ps: '[IO.File]::WriteAllLines([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini"), $conf_ini, ${utf8})' +- ps: move "build_msvc\${env:PLATFORM}\${env:CONFIGURATION}\*.exe" src test_script: -- cmd: build_msvc\%PLATFORM%\%CONFIGURATION%\test_bitcoin.exe +- cmd: src\test_bitcoin.exe +- ps: src\bench_bitcoin.exe -evals=1 -scaling=0 +- ps: python test\util\bitcoin-util-test.py +- cmd: python test\util\rpcauth-test.py +- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude "feature_notifications,wallet_multiwallet,wallet_multiwallet.py --usecli" deploy: off From fa84723e73d3d7766e7821881ac96ec203e50efc Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 17 Sep 2018 14:33:52 -0400 Subject: [PATCH 019/263] amount: Move CAmount CENT to unit test header --- src/amount.h | 1 - src/bench/ccoins_caching.cpp | 16 ++++++++-------- src/test/test_bitcoin.h | 2 ++ src/utilmoneystr.cpp | 2 +- src/wallet/coinselection.h | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/amount.h b/src/amount.h index 2bd367cba2..449fd1b15f 100644 --- a/src/amount.h +++ b/src/amount.h @@ -12,7 +12,6 @@ typedef int64_t CAmount; static const CAmount COIN = 100000000; -static const CAmount CENT = 1000000; /** No amount larger than this (in satoshi) is valid. * diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index db303eeead..b8d82c0a89 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -12,8 +12,8 @@ // FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp. // // Helper: create two dummy transactions, each with -// two outputs. The first has 11 and 50 CENT outputs -// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs +// two outputs. The first has 11 and 50 COIN outputs +// paid to a TX_PUBKEY, the second 21 and 22 COIN outputs // paid to a TX_PUBKEYHASH. // static std::vector @@ -31,16 +31,16 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) // Create some dummy input transactions dummyTransactions[0].vout.resize(2); - dummyTransactions[0].vout[0].nValue = 11 * CENT; + dummyTransactions[0].vout[0].nValue = 11 * COIN; dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - dummyTransactions[0].vout[1].nValue = 50 * CENT; + dummyTransactions[0].vout[1].nValue = 50 * COIN; dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; AddCoins(coinsRet, dummyTransactions[0], 0); dummyTransactions[1].vout.resize(2); - dummyTransactions[1].vout[0].nValue = 21 * CENT; + dummyTransactions[1].vout[0].nValue = 21 * COIN; dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); - dummyTransactions[1].vout[1].nValue = 22 * CENT; + dummyTransactions[1].vout[1].nValue = 22 * COIN; dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); AddCoins(coinsRet, dummyTransactions[1], 0); @@ -72,7 +72,7 @@ static void CCoinsCaching(benchmark::State& state) t1.vin[2].prevout.n = 1; t1.vin[2].scriptSig << std::vector(65, 0) << std::vector(33, 4); t1.vout.resize(2); - t1.vout[0].nValue = 90 * CENT; + t1.vout[0].nValue = 90 * COIN; t1.vout[0].scriptPubKey << OP_1; // Benchmark. @@ -80,7 +80,7 @@ static void CCoinsCaching(benchmark::State& state) bool success = AreInputsStandard(t1, coins); assert(success); CAmount value = coins.GetValueIn(t1); - assert(value == (50 + 21 + 22) * CENT); + assert(value == (50 + 21 + 22) * COIN); } } diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index b87d9bea5d..3872767133 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -37,6 +37,8 @@ static inline uint64_t InsecureRandBits(int bits) { return insecure_rand_ctx.ran static inline uint64_t InsecureRandRange(uint64_t range) { return insecure_rand_ctx.randrange(range); } static inline bool InsecureRandBool() { return insecure_rand_ctx.randbool(); } +static constexpr CAmount CENT{1000000}; + /** Basic testing setup. * This just configures logging and chain parameters. */ diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index a9af59a11d..326ef9b27a 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -48,7 +48,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) if (*p == '.') { p++; - int64_t nMult = CENT*10; + int64_t nMult = COIN / 10; while (isdigit(*p) && (nMult > 0)) { nUnits += nMult * (*p++ - '0'); diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 6d755d0969..5348401f45 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -10,7 +10,7 @@ #include //! target minimum change amount -static const CAmount MIN_CHANGE = CENT; +static constexpr CAmount MIN_CHANGE{COIN / 100}; //! final minimum change amount after paying for fees static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2; From b8f801964f59586508ea8da6cf3decd76bc0e571 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 17 Sep 2018 15:50:55 -0400 Subject: [PATCH 020/263] Fix crash bug with duplicate inputs within a transaction Introduced by #9049 --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 947192be0e..59c3fb425f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3122,7 +3122,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // Check transactions for (const auto& tx : block.vtx) - if (!CheckTransaction(*tx, state, false)) + if (!CheckTransaction(*tx, state, true)) return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); From 9b4a36effcf642f3844c6696b757266686ece11a Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 17 Sep 2018 15:52:01 -0400 Subject: [PATCH 021/263] [qa] Test for duplicate inputs within a transaction --- test/functional/p2p_invalid_block.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index 7be7c9b3ee..0678b1a651 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -81,6 +81,16 @@ def run_test(self): node.p2p.send_blocks_and_test([block2], node, success=False, request_block=False, reject_reason='bad-txns-duplicate') + # Check transactions for duplicate inputs + self.log.info("Test duplicate input block.") + + block2_orig.vtx[2].vin.append(block2_orig.vtx[2].vin[0]) + block2_orig.vtx[2].rehash() + block2_orig.hashMerkleRoot = block2_orig.calc_merkle_root() + block2_orig.rehash() + block2_orig.solve() + node.p2p.send_blocks_and_test([block2_orig], node, success=False, request_block=False, reject_reason='bad-txns-inputs-duplicate') + self.log.info("Test very broken block.") block3 = create_block(tip, create_coinbase(height), block_time) From a2eb6f540538d32725aecf678301a96247db6fd9 Mon Sep 17 00:00:00 2001 From: chris-belcher Date: Wed, 2 May 2018 13:19:40 +0100 Subject: [PATCH 022/263] [rpc] Add getnodeaddresses RPC command New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method. Tests the new rpc call by feeding IP address to a test node via the p2p protocol, then obtaining someone of those addresses with getnodeaddresses and checking that they are a subset. --- doc/release-notes-13152.md | 4 +++ src/rpc/client.cpp | 1 + src/rpc/net.cpp | 53 ++++++++++++++++++++++++++++++++++++++ test/functional/rpc_net.py | 39 ++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 doc/release-notes-13152.md diff --git a/doc/release-notes-13152.md b/doc/release-notes-13152.md new file mode 100644 index 0000000000..72526f5355 --- /dev/null +++ b/doc/release-notes-13152.md @@ -0,0 +1,4 @@ +New RPC methods +------------ + +- `getnodeaddresses` returns peer addresses known to this node. It may be used to connect to nodes over TCP without using the DNS seeds. \ No newline at end of file diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index f4d44fc809..649e222c39 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -163,6 +163,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "rescanblockchain", 0, "start_height"}, { "rescanblockchain", 1, "stop_height"}, { "createwallet", 1, "disable_private_keys"}, + { "getnodeaddresses", 0, "count"}, }; // clang-format on diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 099a7cf1da..846d90cd0a 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -626,6 +626,58 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) return g_connman->GetNetworkActive(); } +static UniValue getnodeaddresses(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 1) { + throw std::runtime_error( + "getnodeaddresses ( count )\n" + "\nReturn known addresses which can potentially be used to find new nodes in the network\n" + "\nArguments:\n" + "1. \"count\" (numeric, optional) How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) + + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses. (default = 1)\n" + "\nResult:\n" + "[\n" + " {\n" + " \"time\": ttt, (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n" + " \"services\": n, (numeric) The services offered\n" + " \"address\": \"host\", (string) The address of the node\n" + " \"port\": n (numeric) The port of the node\n" + " }\n" + " ,....\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getnodeaddresses", "8") + + HelpExampleRpc("getnodeaddresses", "8") + ); + } + if (!g_connman) { + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } + + int count = 1; + if (!request.params[0].isNull()) { + count = request.params[0].get_int(); + if (count <= 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); + } + } + // returns a shuffled list of CAddress + std::vector vAddr = g_connman->GetAddresses(); + UniValue ret(UniValue::VARR); + + int address_return_count = std::min(count, vAddr.size()); + for (int i = 0; i < address_return_count; ++i) { + UniValue obj(UniValue::VOBJ); + const CAddress& addr = vAddr[i]; + obj.pushKV("time", (int)addr.nTime); + obj.pushKV("services", (uint64_t)addr.nServices); + obj.pushKV("address", addr.ToStringIP()); + obj.pushKV("port", addr.GetPort()); + ret.push_back(obj); + } + return ret; +} + // clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames @@ -642,6 +694,7 @@ static const CRPCCommand commands[] = { "network", "listbanned", &listbanned, {} }, { "network", "clearbanned", &clearbanned, {} }, { "network", "setnetworkactive", &setnetworkactive, {"state"} }, + { "network", "getnodeaddresses", &getnodeaddresses, {"count"} }, }; // clang-format on diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index a46518200c..1e525214fa 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -13,11 +13,14 @@ from test_framework.util import ( assert_equal, assert_greater_than_or_equal, + assert_greater_than, assert_raises_rpc_error, connect_nodes_bi, p2p_port, wait_until, ) +from test_framework.mininode import P2PInterface +from test_framework.messages import CAddress, msg_addr, NODE_NETWORK, NODE_WITNESS class NetTest(BitcoinTestFramework): def set_test_params(self): @@ -31,6 +34,7 @@ def run_test(self): self._test_getnetworkinginfo() self._test_getaddednodeinfo() self._test_getpeerinfo() + self._test_getnodeaddresses() def _test_connection_count(self): # connect_nodes_bi connects each node to the other @@ -101,5 +105,40 @@ def _test_getpeerinfo(self): assert_equal(peer_info[0][0]['minfeefilter'], Decimal("0.00000500")) assert_equal(peer_info[1][0]['minfeefilter'], Decimal("0.00001000")) + def _test_getnodeaddresses(self): + self.nodes[0].add_p2p_connection(P2PInterface()) + + # send some addresses to the node via the p2p message addr + msg = msg_addr() + imported_addrs = [] + for i in range(256): + a = "123.123.123.{}".format(i) + imported_addrs.append(a) + addr = CAddress() + addr.time = 100000000 + addr.nServices = NODE_NETWORK | NODE_WITNESS + addr.ip = a + addr.port = 8333 + msg.addrs.append(addr) + self.nodes[0].p2p.send_and_ping(msg) + + # obtain addresses via rpc call and check they were ones sent in before + REQUEST_COUNT = 10 + node_addresses = self.nodes[0].getnodeaddresses(REQUEST_COUNT) + assert_equal(len(node_addresses), REQUEST_COUNT) + for a in node_addresses: + assert_greater_than(a["time"], 1527811200) # 1st June 2018 + assert_equal(a["services"], NODE_NETWORK | NODE_WITNESS) + assert a["address"] in imported_addrs + assert_equal(a["port"], 8333) + + assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1) + + # addrman's size cannot be known reliably after insertion, as hash collisions may occur + # so only test that requesting a large number of addresses returns less than that + LARGE_REQUEST_COUNT = 10000 + node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT) + assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses)) + if __name__ == '__main__': NetTest().main() From fd5c95cc4ec8d7d8a49539e9143eab29281c00f7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 18 Sep 2018 09:25:26 +0200 Subject: [PATCH 023/263] doc: Add historical release notes for 0.16.3 --- doc/release-notes/release-notes-0.16.3.md | 88 +++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 doc/release-notes/release-notes-0.16.3.md diff --git a/doc/release-notes/release-notes-0.16.3.md b/doc/release-notes/release-notes-0.16.3.md new file mode 100644 index 0000000000..2e52d309c2 --- /dev/null +++ b/doc/release-notes/release-notes-0.16.3.md @@ -0,0 +1,88 @@ +Bitcoin Core version 0.16.3 is now available from: + + + +This is a new minor version release, with various bugfixes. + +Please report bugs using the issue tracker at GitHub: + + + +To receive security and update notifications, please subscribe to: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0 or newer, your chainstate database will be converted to a +new format, which will take anywhere from a few minutes to half an hour, +depending on the speed of your machine. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0 or higher. Upgrading +directly from 0.7.x and earlier without re-downloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +Wallets created in 0.16 and later are not compatible with versions prior to 0.16 +and will not work if you try to use newly created wallets in older versions. Existing +wallets that were created with older versions are not affected by this. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notable changes +=============== + +Denial-of-Service vulnerability +------------------------------- + +A denial-of-service vulnerability (CVE-2018-17144) exploitable by miners has +been discovered in Bitcoin Core versions 0.14.0 up to 0.16.2. It is recommended +to upgrade any of the vulnerable versions to 0.16.3 as soon as possible. + +0.16.3 change log +------------------ + +### Consensus +- #14249 `696b936` Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar) + +### RPC and other APIs +- #13547 `212ef1f` Make `signrawtransaction*` give an error when amount is needed but missing (ajtowns) + +### Miscellaneous +- #13655 `1cdbea7` bitcoinconsensus: invalid flags error should be set to `bitcoinconsensus_err` (afk11) + +### Documentation +- #13844 `11b9dbb` correct the help output for -prune (hebasto) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Anthony Towns +- Hennadii Stepanov +- Matt Corallo +- Suhas Daftuar +- Thomas Kerin +- Wladimir J. van der Laan + +And to those that reported security issues: + +- (anonymous reporter) + From 00000090157024b42ae0d6f2d4be8c22f5e096a5 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 18 Sep 2018 20:43:59 -0400 Subject: [PATCH 024/263] doc: Split depends installation instructions per arch --- depends/README.md | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/depends/README.md b/depends/README.md index 73bfc8b726..48f8675056 100644 --- a/depends/README.md +++ b/depends/README.md @@ -30,21 +30,34 @@ Common `host-platform-triplets` for cross compilation are: No other options are needed, the paths are automatically configured. -Install the required dependencies: Ubuntu & Debian --------------------------------------------------- +### Install the required dependencies: Ubuntu & Debian -For macOS cross compilation: +First, install the common dependencies: - sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python-setuptools + sudo apt-get install autoconf automake cmake bsdmainutils ca-certificates curl faketime g++ libtool pkg-config -For Win32/Win64 cross compilation: +#### For macOS cross compilation: + + sudo apt-get install librsvg2-bin libtiff-tools imagemagick libcap-dev libz-dev libbz2-dev python-setuptools + +#### For Win32/Win64 cross compilation: - see [build-windows.md](../doc/build-windows.md#cross-compilation-for-ubuntu-and-windows-subsystem-for-linux) -For linux (including i386, ARM) cross compilation: +#### For linux (including i386, ARM) cross compilation: + +Common linux dependencies: + + sudo apt-get install g++-multilib binutils-gold bsdmainutils + +For linux ARM cross compilation: + + sudo apt-get install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu - sudo apt-get install curl g++-aarch64-linux-gnu g++-4.8-aarch64-linux-gnu gcc-4.8-aarch64-linux-gnu binutils-aarch64-linux-gnu g++-arm-linux-gnueabihf g++-4.8-arm-linux-gnueabihf gcc-4.8-arm-linux-gnueabihf binutils-arm-linux-gnueabihf g++-4.8-multilib gcc-4.8-multilib binutils-gold bsdmainutils +For linux AARCH64 cross compilation: + sudo apt-get install g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf + For linux RISC-V 64-bit cross compilation (there are no packages for 32-bit): sudo apt-get install curl g++-riscv64-linux-gnu binutils-riscv64-linux-gnu @@ -52,7 +65,7 @@ For linux RISC-V 64-bit cross compilation (there are no packages for 32-bit): RISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_bitcoin` executable (see https://github.com/bitcoin/bitcoin/pull/13543), this is apparently fixed in gcc-8.1.0. -Dependency Options: +### Dependency Options The following can be set when running make: make FOO=bar SOURCES_PATH: downloaded sources will be placed here @@ -70,7 +83,7 @@ The following can be set when running make: make FOO=bar If some packages are not built, for example `make NO_WALLET=1`, the appropriate options will be passed to bitcoin's configure. In this case, `--disable-wallet`. -Additional targets: +### Additional targets download: run 'make download' to fetch all sources without building them download-osx: run 'make download-osx' to fetch all sources needed for macOS builds From a23a7f60aa07de52d23ff1f2034fc43926ec3520 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 27 Jun 2018 18:06:44 +0200 Subject: [PATCH 025/263] wallet: Avoid potential use of unitialized value bnb_used in CWallet::CreateTransaction(...) --- src/wallet/wallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d0857bcb72..49743ee02a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2844,6 +2844,8 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CTransac return false; } } + } else { + bnb_used = false; } const CAmount nChange = nValueIn - nValueToSelect; From fad95e8da60d8eceb54a92be513941d7d04c1eb9 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 18 Sep 2018 21:11:49 -0400 Subject: [PATCH 026/263] doc: Split build linux dependencies --- depends/README.md | 22 +++++++++------------- doc/build-unix.md | 8 ++++++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/depends/README.md b/depends/README.md index 48f8675056..693bc36197 100644 --- a/depends/README.md +++ b/depends/README.md @@ -32,35 +32,31 @@ No other options are needed, the paths are automatically configured. ### Install the required dependencies: Ubuntu & Debian -First, install the common dependencies: +#### For macOS cross compilation - sudo apt-get install autoconf automake cmake bsdmainutils ca-certificates curl faketime g++ libtool pkg-config + sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python-setuptools -#### For macOS cross compilation: - - sudo apt-get install librsvg2-bin libtiff-tools imagemagick libcap-dev libz-dev libbz2-dev python-setuptools - -#### For Win32/Win64 cross compilation: +#### For Win32/Win64 cross compilation - see [build-windows.md](../doc/build-windows.md#cross-compilation-for-ubuntu-and-windows-subsystem-for-linux) -#### For linux (including i386, ARM) cross compilation: +#### For linux (including i386, ARM) cross compilation Common linux dependencies: - sudo apt-get install g++-multilib binutils-gold bsdmainutils + sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 For linux ARM cross compilation: - sudo apt-get install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + sudo apt-get install g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf For linux AARCH64 cross compilation: - sudo apt-get install g++-arm-linux-gnueabihf binutils-arm-linux-gnueabihf - + sudo apt-get install g++-aarch64-linux-gnu binutils-aarch64-linux-gnu + For linux RISC-V 64-bit cross compilation (there are no packages for 32-bit): - sudo apt-get install curl g++-riscv64-linux-gnu binutils-riscv64-linux-gnu + sudo apt-get install g++-riscv64-linux-gnu binutils-riscv64-linux-gnu RISC-V known issue: gcc-7.3.0 and gcc-7.3.1 result in a broken `test_bitcoin` executable (see https://github.com/bitcoin/bitcoin/pull/13543), this is apparently fixed in gcc-8.1.0. diff --git a/doc/build-unix.md b/doc/build-unix.md index dfeb8ba260..82cd59be4f 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -70,7 +70,11 @@ tuned to conserve memory with additional CXXFLAGS: Build requirements: - sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils python3 libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev + sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 + +Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: + + sudo apt-get libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev BerkeleyDB is required for the wallet. @@ -97,7 +101,7 @@ ZMQ dependencies (provides ZMQ API): sudo apt-get install libzmq3-dev -#### Dependencies for the GUI +GUI dependencies: If you want to build bitcoin-qt, make sure that the required packages for Qt development are installed. Qt 5 is necessary to build the GUI. From b6718e373ed425fa2440ddd8f1b05c76b782dc2b Mon Sep 17 00:00:00 2001 From: practicalswift Date: Fri, 21 Sep 2018 11:03:21 +0200 Subject: [PATCH 027/263] tests: Use MakeUnique to construct objects owned by unique_ptrs --- doc/developer-notes.md | 5 +++++ src/bench/bench_bitcoin.cpp | 2 +- src/bench/coin_selection.cpp | 2 +- src/test/allocator_tests.cpp | 2 +- src/test/checkqueue_tests.cpp | 14 +++++++------- src/test/net_tests.cpp | 4 ++-- src/test/test_bitcoin.cpp | 2 +- src/test/test_bitcoin_fuzzy.cpp | 2 +- src/wallet/test/coinselector_tests.cpp | 2 +- 9 files changed, 20 insertions(+), 15 deletions(-) diff --git a/doc/developer-notes.md b/doc/developer-notes.md index da8384c537..bdb8d7dbae 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -439,6 +439,11 @@ General C++ - *Rationale*: This avoids memory and resource leaks, and ensures exception safety +- Use `MakeUnique()` to construct objects owned by `unique_ptr`s + + - *Rationale*: `MakeUnique` is concise and ensures exception safety in complex expressions. + `MakeUnique` is a temporary project local implementation of `std::make_unique` (C++14). + C++ data structures -------------------- diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index d7b8083e7c..4fa516cb81 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -82,7 +82,7 @@ int main(int argc, char** argv) return EXIT_FAILURE; } - std::unique_ptr printer(new benchmark::ConsolePrinter()); + std::unique_ptr printer = MakeUnique(); std::string printer_arg = gArgs.GetArg("-printer", DEFAULT_BENCH_PRINTER); if ("plot" == printer_arg) { printer.reset(new benchmark::PlotlyPrinter( diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 0a6f5d85ea..27c23d6834 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -66,7 +66,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector CMutableTransaction tx; tx.vout.resize(nInput + 1); tx.vout[nInput].nValue = nValue; - std::unique_ptr wtx(new CWalletTx(&testWallet, MakeTransactionRef(std::move(tx)))); + std::unique_ptr wtx = MakeUnique(&testWallet, MakeTransactionRef(std::move(tx))); set.emplace_back(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0); wtxn.emplace_back(std::move(wtx)); } diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 1052ada232..c72c062b81 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -163,7 +163,7 @@ class TestLockedPageAllocator: public LockedPageAllocator BOOST_AUTO_TEST_CASE(lockedpool_tests_mock) { // Test over three virtual arenas, of which one will succeed being locked - std::unique_ptr x(new TestLockedPageAllocator(3, 1)); + std::unique_ptr x = MakeUnique(3, 1); LockedPool pool(std::move(x)); BOOST_CHECK(pool.stats().total == 0); BOOST_CHECK(pool.stats().locked == 0); diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 2732598b4f..f4b416c4ca 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -148,7 +148,7 @@ typedef CCheckQueue FrozenCleanup_Queue; */ static void Correct_Queue_range(std::vector range) { - auto small_queue = std::unique_ptr(new Correct_Queue {QUEUE_BATCH_SIZE}); + auto small_queue = MakeUnique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&]{small_queue->Thread();}); @@ -213,7 +213,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) /** Test that failing checks are caught */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) { - auto fail_queue = std::unique_ptr(new Failing_Queue {QUEUE_BATCH_SIZE}); + auto fail_queue = MakeUnique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { @@ -246,7 +246,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) // future blocks, ie, the bad state is cleared. BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) { - auto fail_queue = std::unique_ptr(new Failing_Queue {QUEUE_BATCH_SIZE}); + auto fail_queue = MakeUnique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&]{fail_queue->Thread();}); @@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) // more than once as well BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) { - auto queue = std::unique_ptr(new Unique_Queue {QUEUE_BATCH_SIZE}); + auto queue = MakeUnique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&]{queue->Thread();}); @@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) // time could leave the data hanging across a sequence of blocks. BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) { - auto queue = std::unique_ptr(new Memory_Queue {QUEUE_BATCH_SIZE}); + auto queue = MakeUnique(QUEUE_BATCH_SIZE); boost::thread_group tg; for (auto x = 0; x < nScriptCheckThreads; ++x) { tg.create_thread([&]{queue->Thread();}); @@ -341,7 +341,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) // have been destructed BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) { - auto queue = std::unique_ptr(new FrozenCleanup_Queue {QUEUE_BATCH_SIZE}); + auto queue = MakeUnique(QUEUE_BATCH_SIZE); boost::thread_group tg; bool fails = false; for (auto x = 0; x < nScriptCheckThreads; ++x) { @@ -384,7 +384,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) /** Test that CCheckQueueControl is threadsafe */ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) { - auto queue = std::unique_ptr(new Standard_Queue{QUEUE_BATCH_SIZE}); + auto queue = MakeUnique(QUEUE_BATCH_SIZE); { boost::thread_group tg; std::atomic nThreads {0}; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index eaa8b16182..35a143957e 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -179,12 +179,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) bool fInboundIn = false; // Test that fFeeler is false by default. - std::unique_ptr pnode1(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn)); + std::unique_ptr pnode1 = MakeUnique(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn); BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fFeeler == false); fInboundIn = true; - std::unique_ptr pnode2(new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn)); + std::unique_ptr pnode2 = MakeUnique(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn); BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fFeeler == false); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 0d7c9f0abf..766e34e5b5 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -107,7 +107,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); - g_connman = std::unique_ptr(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. + g_connman = MakeUnique(0x1337, 0x1337); // Deterministic randomness for tests. connman = g_connman.get(); peerLogic.reset(new PeerLogicValidation(connman, scheduler, /*enable_bip61=*/true)); } diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp index 11b7c66ccd..88c082ff66 100644 --- a/src/test/test_bitcoin_fuzzy.cpp +++ b/src/test/test_bitcoin_fuzzy.cpp @@ -279,7 +279,7 @@ static int test_one_input(std::vector buffer) { static std::unique_ptr globalVerifyHandle; void initialize() { - globalVerifyHandle = std::unique_ptr(new ECCVerifyHandle()); + globalVerifyHandle = MakeUnique(); } // This function is used by libFuzzer diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 6d1d09d5a5..21857df081 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -65,7 +65,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa // so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe() tx.vin.resize(1); } - std::unique_ptr wtx(new CWalletTx(&testWallet, MakeTransactionRef(std::move(tx)))); + std::unique_ptr wtx = MakeUnique(&testWallet, MakeTransactionRef(std::move(tx))); if (fIsFromMe) { wtx->fDebitCached = true; From fa910e43014d7b6a22f95e2c65b1c4a3e8d5cedc Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 19 Sep 2018 16:37:50 -0400 Subject: [PATCH 028/263] init: Remove deprecated args from hidden args --- src/bitcoin-cli.cpp | 5 ----- src/httpserver.cpp | 7 ------- src/init.cpp | 23 ++--------------------- test/lint/check-doc.py | 2 +- 4 files changed, 3 insertions(+), 34 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 53c3821ce5..09507fd249 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -139,11 +139,6 @@ static int AppInitRPC(int argc, char* argv[]) fprintf(stderr, "Error: %s\n", e.what()); return EXIT_FAILURE; } - if (gArgs.GetBoolArg("-rpcssl", false)) - { - fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n"); - return EXIT_FAILURE; - } return CONTINUE_EXECUTION; } diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 326f7f6b64..9aaa1024da 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -352,13 +352,6 @@ bool InitHTTPServer() if (!InitHTTPAllowList()) return false; - if (gArgs.GetBoolArg("-rpcssl", false)) { - uiInterface.ThreadSafeMessageBox( - "SSL mode for RPC (-rpcssl) is no longer supported.", - "", CClientUIInterface::MSG_ERROR); - return false; - } - // Redirect libevent's logging to our own log event_set_log_callback(&libevent_log_cb); // Update libevent's log handling. Returns false if our version of diff --git a/src/init.cpp b/src/init.cpp index 93568c97a9..9386c46ce7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -322,8 +322,8 @@ void SetupServerArgs() const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST); // Hidden Options - std::vector hidden_args = {"-rpcssl", "-benchmark", "-h", "-help", "-socks", "-tor", "-debugnet", "-whitelistalwaysrelay", - "-prematurewitness", "-walletprematurewitness", "-promiscuousmempoolflags", "-blockminsize", "-dbcrashratio", "-forcecompactdb", "-usehd", + std::vector hidden_args = {"-h", "-help", + "-dbcrashratio", "-forcecompactdb", "-usehd", // GUI args. These will be overwritten by SetupUIArgs for the GUI "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=", "-min", "-resetguisettings", "-rootcertificates=", "-splash", "-uiplatform"}; @@ -961,25 +961,6 @@ bool AppInitParameterInteraction() } } - // Check for -debugnet - if (gArgs.GetBoolArg("-debugnet", false)) - InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net.")); - // Check for -socks - as this is a privacy risk to continue, exit here - if (gArgs.IsArgSet("-socks")) - return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); - // Check for -tor - as this is a privacy risk to continue, exit here - if (gArgs.GetBoolArg("-tor", false)) - return InitError(_("Unsupported argument -tor found, use -onion.")); - - if (gArgs.GetBoolArg("-benchmark", false)) - InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench.")); - - if (gArgs.GetBoolArg("-whitelistalwaysrelay", false)) - InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); - - if (gArgs.IsArgSet("-blockminsize")) - InitWarning("Unsupported argument -blockminsize ignored."); - // Checkmempool and checkblockindex default to true in regtest mode int ratio = std::min(std::max(gArgs.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); if (ratio != 0) { diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py index 0c4a603167..7b056dab32 100755 --- a/test/lint/check-doc.py +++ b/test/lint/check-doc.py @@ -22,7 +22,7 @@ CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST) CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR) # list unsupported, deprecated and duplicate args as they need no documentation -SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb', '-usehd']) +SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb', '-usehd']) def main(): From 52beb9ed8876e3129360197ac632c1b59f910c55 Mon Sep 17 00:00:00 2001 From: Walter Date: Thu, 20 Sep 2018 13:57:29 +0200 Subject: [PATCH 029/263] Add autogen.sh in ARM Cross-compilation autogen for the config files was missing. --- doc/build-unix.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/build-unix.md b/doc/build-unix.md index dfeb8ba260..3f8848abf2 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -278,6 +278,7 @@ To build executables for ARM: cd depends make HOST=arm-linux-gnueabihf NO_QT=1 cd .. + ./autogen.sh ./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ make From fa6b30c40b84b58f9c5327481a91292e23ed3a7c Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 20 Sep 2018 14:03:00 -0400 Subject: [PATCH 030/263] lcov: filter /usr/lib/ from coverage reports --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 10dda65b21..eec9f72215 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,7 +168,7 @@ $(BITCOIN_CLI_BIN): FORCE $(MAKE) -C src $(@F) if USE_LCOV -LCOV_FILTER_PATTERN=-p "/usr/include/" -p "src/leveldb/" -p "src/bench/" -p "src/univalue" -p "src/crypto/ctaes" -p "src/secp256k1" +LCOV_FILTER_PATTERN=-p "/usr/include/" -p "/usr/lib/" -p "src/leveldb/" -p "src/bench/" -p "src/univalue" -p "src/crypto/ctaes" -p "src/secp256k1" baseline.info: $(LCOV) -c -i -d $(abs_builddir)/src -o $@ From 25548b295861c19ad0c25319df727216f81f21a8 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 20 Sep 2018 16:41:08 -0400 Subject: [PATCH 031/263] [wallet] Remove -usehd --- src/init.cpp | 2 +- src/wallet/wallet.cpp | 14 -------------- test/functional/wallet_hd.py | 6 ------ test/lint/check-doc.py | 2 +- 4 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 9386c46ce7..119c79338c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -323,7 +323,7 @@ void SetupServerArgs() // Hidden Options std::vector hidden_args = {"-h", "-help", - "-dbcrashratio", "-forcecompactdb", "-usehd", + "-dbcrashratio", "-forcecompactdb", // GUI args. These will be overwritten by SetupUIArgs for the GUI "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=", "-min", "-resetguisettings", "-rootcertificates=", "-splash", "-uiplatform"}; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7f7a88e986..83a0fb62cc 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3987,10 +3987,6 @@ std::shared_ptr CWallet::CreateWalletFromFile(const std::string& name, if (fFirstRun) { // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key - if (!gArgs.GetBoolArg("-usehd", true)) { - InitError(strprintf(_("Error creating %s: You can't create non-HD wallets with this version."), walletFile)); - return nullptr; - } walletInstance->SetMinVersion(FEATURE_LATEST); if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { @@ -4018,16 +4014,6 @@ std::shared_ptr CWallet::CreateWalletFromFile(const std::string& name, if (!walletInstance->mapKeys.empty() || !walletInstance->mapCryptedKeys.empty()) { InitWarning(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile)); } - } else if (gArgs.IsArgSet("-usehd")) { - bool useHD = gArgs.GetBoolArg("-usehd", true); - if (walletInstance->IsHDEnabled() && !useHD) { - InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile)); - return nullptr; - } - if (!walletInstance->IsHDEnabled() && useHD) { - InitError(strprintf(_("Error loading %s: You can't enable HD on an already existing non-HD wallet"), walletFile)); - return nullptr; - } } if (!gArgs.GetArg("-addresstype", "").empty() && !ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) { diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 48e71f6c40..eb42531693 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -25,12 +25,6 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() def run_test(self): - # Make sure can't switch off usehd after wallet creation - self.stop_node(1) - self.nodes[1].assert_start_raises_init_error(['-usehd=0'], "Error: Error loading : You can't disable HD on an already existing HD wallet") - self.start_node(1) - connect_nodes_bi(self.nodes, 0, 1) - # Make sure we use hd, keep masterkeyid masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert_equal(masterkeyid, self.nodes[1].getwalletinfo()['hdmasterkeyid']) diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py index 7b056dab32..b0d9f87958 100755 --- a/test/lint/check-doc.py +++ b/test/lint/check-doc.py @@ -22,7 +22,7 @@ CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST) CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR) # list unsupported, deprecated and duplicate args as they need no documentation -SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb', '-usehd']) +SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb']) def main(): From f8c1714634445542a16ac01d128d8ad2b2810e19 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 11 Sep 2018 00:13:19 -0400 Subject: [PATCH 032/263] Convert non-witness UTXOs to witness if witness sig created If a witness signature was created when a non-witness UTXO is used, convert the non-witness UTXO to a witness one. --- src/script/sign.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index d779910425..83cc210b30 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -277,6 +277,11 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t if (require_witness_sig && !sigdata.witness) return false; input.FromSignatureData(sigdata); + if (sigdata.witness) { + assert(!utxo.IsNull()); + input.witness_utxo = utxo; + } + // If both UTXO types are present, drop the unnecessary one. if (input.non_witness_utxo && !input.witness_utxo.IsNull()) { if (sigdata.witness) { From 862d159d635c1de219d94e030b186a745fe28eb9 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 20 Sep 2018 11:43:06 -0700 Subject: [PATCH 033/263] Add test for conversion from non-witness to witness UTXO --- test/functional/rpc_psbt.py | 47 ++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 54dc871448..fca910bf64 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -6,7 +6,7 @@ """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, find_output +from test_framework.util import assert_equal, assert_raises_rpc_error, find_output, disconnect_nodes, connect_nodes_bi, sync_blocks import json import os @@ -23,6 +23,45 @@ def set_test_params(self): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + def test_utxo_conversion(self): + mining_node = self.nodes[2] + offline_node = self.nodes[0] + online_node = self.nodes[1] + + # Disconnect offline node from others + disconnect_nodes(offline_node, 1) + disconnect_nodes(online_node, 0) + disconnect_nodes(offline_node, 2) + disconnect_nodes(mining_node, 0) + + # Mine a transaction that credits the offline address + offline_addr = offline_node.getnewaddress(address_type="p2sh-segwit") + online_addr = online_node.getnewaddress(address_type="p2sh-segwit") + online_node.importaddress(offline_addr, "", False) + mining_node.sendtoaddress(address=offline_addr, amount=1.0) + mining_node.generate(nblocks=1) + sync_blocks([mining_node, online_node]) + + # Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO) + utxos = online_node.listunspent(addresses=[offline_addr]) + raw = online_node.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}]) + psbt = online_node.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"] + assert("non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]) + + # Have the offline node sign the PSBT (which will update the UTXO to segwit) + signed_psbt = offline_node.walletprocesspsbt(psbt)["psbt"] + assert("witness_utxo" in mining_node.decodepsbt(signed_psbt)["inputs"][0]) + + # Make sure we can mine the resulting transaction + txid = mining_node.sendrawtransaction(mining_node.finalizepsbt(signed_psbt)["hex"]) + mining_node.generate(1) + sync_blocks([mining_node, online_node]) + assert_equal(online_node.gettxout(txid,0)["confirmations"], 1) + + # Reconnect + connect_nodes_bi(self.nodes, 0, 1) + connect_nodes_bi(self.nodes, 0, 2) + def run_test(self): # Create and fund a raw tx for sending 10 BTC psbtx1 = self.nodes[0].walletcreatefundedpsbt([], {self.nodes[2].getnewaddress():10})['psbt'] @@ -224,6 +263,12 @@ def run_test(self): extracted = self.nodes[2].finalizepsbt(extractor['extract'], True)['hex'] assert_equal(extracted, extractor['result']) + # Unload extra wallets + for i, signer in enumerate(signers): + self.nodes[2].unloadwallet("wallet{}".format(i)) + + self.test_utxo_conversion() + if __name__ == '__main__': PSBTTest().main() From 2c3eade704f63b360926de9e975ce80143781679 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sat, 4 Aug 2018 16:39:14 +0000 Subject: [PATCH 034/263] Make fs::path::string() always return utf-8 string --- src/fs.h | 1 - src/qt/guiutil.cpp | 6 ++---- src/util.cpp | 4 ++++ test/lint/lint-includes.sh | 1 - 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fs.h b/src/fs.h index 5492bdd4ec..a7074f446a 100644 --- a/src/fs.h +++ b/src/fs.h @@ -10,7 +10,6 @@ #include #include -#include /** Filesystem operations and types */ namespace fs = boost::filesystem; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 7afe25d25a..b894fc8166 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -60,8 +60,6 @@ #include #endif -static fs::detail::utf8_codecvt_facet utf8; - namespace GUIUtil { QString dateTimeStr(const QDateTime &date) @@ -764,12 +762,12 @@ void setClipboard(const QString& str) fs::path qstringToBoostPath(const QString &path) { - return fs::path(path.toStdString(), utf8); + return fs::path(path.toStdString()); } QString boostPathToQString(const fs::path &path) { - return QString::fromStdString(path.string(utf8)); + return QString::fromStdString(path.string()); } QString formatDurationStr(int secs) diff --git a/src/util.cpp b/src/util.cpp index 75a387d7ec..fa624aee90 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1206,7 +1206,11 @@ void SetupEnvironment() // A dummy locale is used to extract the internal default locale, used by // fs::path, which is then used to explicitly imbue the path. std::locale loc = fs::path::imbue(std::locale::classic()); +#ifndef WIN32 fs::path::imbue(loc); +#else + fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16())); +#endif } bool SetupNetworking() diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index a3e7681d45..f6d0fd382b 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -54,7 +54,6 @@ EXPECTED_BOOST_INCLUDES=( boost/chrono/chrono.hpp boost/date_time/posix_time/posix_time.hpp boost/filesystem.hpp - boost/filesystem/detail/utf8_codecvt_facet.hpp boost/filesystem/fstream.hpp boost/multi_index/hashed_index.hpp boost/multi_index/ordered_index.hpp From 1eb9a9b524a82157e65180e85a832bd721388459 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 23:27:01 -0400 Subject: [PATCH 035/263] [RPC] Remove warning for removed estimatefee RPC The RPC was removed in a previous version, but a warning was left for users to use the estimatesmartfee RPC. Remove that warning now that estimatefee has been gone for over one version. --- src/rpc/mining.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index b1bea85fef..809f614301 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -795,12 +795,6 @@ static UniValue submitheader(const JSONRPCRequest& request) throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason()); } -static UniValue estimatefee(const JSONRPCRequest& request) -{ - throw JSONRPCError(RPC_METHOD_DEPRECATED, "estimatefee was removed in v0.17.\n" - "Clients should use estimatesmartfee."); -} - static UniValue estimatesmartfee(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) @@ -978,7 +972,6 @@ static const CRPCCommand commands[] = { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} }, - { "hidden", "estimatefee", &estimatefee, {} }, { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} }, { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, From fae9e84cbb519d835d5a7a88b77ddb4ddd009e8a Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 13 Sep 2018 19:01:00 -0400 Subject: [PATCH 036/263] doc: Add GitHub pr template --- .github/PULL_REQUEST_TEMPLATE.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..00d5478c4e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ +Pull requests without a rationale and clear improvement may be closed +immediately. + +Please provide clear motivation for your patch and explain how it improves +Bitcoin Core user experience or Bitcoin Core developer experience +significantly. + +* Any test improvements or new tests that improve coverage are always welcome. +* All other changes should have accompanying unit tests (see `src/test/`) or + functional tests (see `test/`). Contributors should note which tests cover + modified code. If no tests exist for a region of modified code, new tests + should accompany the change. +* Bug fixes are most welcome when they come with steps to reproduce or an + explanation of the potential issue as well as reasoning for the way the bug + was fixed. +* Features are welcome, but might be rejected due to design or scope issues. + If a feature is based on a lot of dependencies, contributors should first + consider building the system outside of Bitcoin Core, if possible. +* Refactoring changes are only accepted if they are required for a feature or + bug fix or otherwise improve developer experience significantly. For example, + most "code style" refactoring changes require a thorough explanation why they + are useful, what downsides they have and why they *significantly* improve + developer experience or avoid serious programming bugs. Note that code style + is often a subjective matter. Unless they are explicitly mentioned to be + preferred in the [developer notes](/doc/developer-notes.md), stylistic code + changes are usually rejected. + +Bitcoin Core has a thorough review process and even the most trivial change +needs to pass a lot of eyes and requires non-zero or even substantial time +effort to review. There is a huge lack of active reviewers on the project, so +patches often sit for a long time. From 67d7d67cf32d3652dc1a06a6835c9c3d8b2f38ff Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sun, 23 Sep 2018 08:50:47 -0400 Subject: [PATCH 037/263] [test] Fix flake8 warnings in tests Fix all flake8 warnings in tests that are about to be updated to remove addwitnessaddress --- test/functional/feature_nulldummy.py | 12 ++-- test/functional/feature_segwit.py | 104 +++++++++++++-------------- test/functional/p2p_compactblocks.py | 32 ++++----- test/functional/wallet_bumpfee.py | 15 ++-- test/functional/wallet_dump.py | 11 ++- 5 files changed, 82 insertions(+), 92 deletions(-) diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index a79cc3d34b..f51d5ca4fe 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -12,6 +12,7 @@ [Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block. [Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block. """ +import time from test_framework.blocktools import create_coinbase, create_block, create_transaction, add_witness_commitment from test_framework.messages import CTransaction @@ -19,8 +20,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str -import time - NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)" def trueDummy(tx): @@ -53,11 +52,11 @@ def run_test(self): self.wit_address = self.nodes[0].addwitnessaddress(self.address) self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address'] - self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 + self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 coinbase_txid = [] for i in self.coinbase_blocks: coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0]) - self.nodes[0].generate(427) # Block 429 + self.nodes[0].generate(427) # Block 429 self.lastblockhash = self.nodes[0].getbestblockhash() self.tip = int("0x" + self.lastblockhash, 0) self.lastblockheight = 429 @@ -82,7 +81,7 @@ def run_test(self): self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation") test4tx = create_transaction(self.nodes[0], test2tx.hash, self.address, amount=46) - test6txs=[CTransaction(test4tx)] + test6txs = [CTransaction(test4tx)] trueDummy(test4tx) assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True) self.block_submit(self.nodes[0], [test4tx]) @@ -99,8 +98,7 @@ def run_test(self): self.nodes[0].sendrawtransaction(bytes_to_hex_str(i.serialize_with_witness()), True) self.block_submit(self.nodes[0], test6txs, True, True) - - def block_submit(self, node, txs, witness = False, accept = False): + def block_submit(self, node, txs, witness=False, accept=False): block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1) block.nVersion = 4 for tx in txs: diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 2cbfc26e89..fcf175cb2e 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -5,6 +5,7 @@ """Test the SegWit changeover logic.""" from decimal import Decimal +from io import BytesIO from test_framework.address import ( key_to_p2pkh, @@ -21,8 +22,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes, hex_str_to_bytes, sync_blocks, try_rpc -from io import BytesIO - NODE_0 = 0 NODE_2 = 2 WIT_V0 = 0 @@ -91,9 +90,8 @@ def skip_mine(self, node, txid, sign, redeem_script=""): def fail_accept(self, node, error_msg, txid, sign, redeem_script=""): assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script) - def run_test(self): - self.nodes[0].generate(161) #block 161 + self.nodes[0].generate(161) # block 161 self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork") txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) @@ -103,18 +101,18 @@ def run_test(self): assert(tmpl['sigoplimit'] == 20000) assert(tmpl['transactions'][0]['hash'] == txid) assert(tmpl['transactions'][0]['sigops'] == 2) - tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']}) + tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']}) assert(tmpl['sizelimit'] == 1000000) assert('weightlimit' not in tmpl) assert(tmpl['sigoplimit'] == 20000) assert(tmpl['transactions'][0]['hash'] == txid) assert(tmpl['transactions'][0]['sigops'] == 2) - self.nodes[0].generate(1) #block 162 + self.nodes[0].generate(1) # block 162 balance_presetup = self.nodes[0].getbalance() self.pubkey = [] - p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh - wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness + p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh + wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness for i in range(3): newaddress = self.nodes[i].getnewaddress() self.pubkey.append(self.nodes[i].getaddressinfo(newaddress)["pubkey"]) @@ -139,32 +137,32 @@ def run_test(self): wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999"))) p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999"))) - self.nodes[0].generate(1) #block 163 + self.nodes[0].generate(1) # block 163 sync_blocks(self.nodes) # Make sure all nodes recognize the transactions as theirs - assert_equal(self.nodes[0].getbalance(), balance_presetup - 60*50 + 20*Decimal("49.999") + 50) - assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999")) - assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999")) + assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50) + assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999")) + assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999")) - self.nodes[0].generate(260) #block 423 + self.nodes[0].generate(260) # block 423 sync_blocks(self.nodes) self.log.info("Verify witness txs are skipped for mining before the fork") - self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424 - self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425 - self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426 - self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427 + self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) # block 424 + self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) # block 425 + self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) # block 426 + self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) # block 427 self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid") self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False) self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False) - self.nodes[2].generate(4) # blocks 428-431 + self.nodes[2].generate(4) # blocks 428-431 self.log.info("Verify previous witness txs skipped for mining can now be mined") assert_equal(len(self.nodes[2].getrawmempool()), 4) - block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3) + block = self.nodes[2].generate(1) # block 432 (first block with new rules; 432 = 144 * 3) sync_blocks(self.nodes) assert_equal(len(self.nodes[2].getrawmempool()), 0) segwit_tx_list = self.nodes[2].getblock(block[0])["tx"] @@ -181,8 +179,8 @@ def run_test(self): self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0])) self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") - assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) - assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) + assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) + assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) for i in range(len(segwit_tx_list)): tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i])) @@ -198,21 +196,21 @@ def run_test(self): self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness) (code 64)', p2sh_ids[NODE_2][WIT_V1][2], sign=False, redeem_script=witness_script(True, self.pubkey[2])) self.log.info("Verify default node can now use witness txs") - self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432 - self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433 - self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434 - self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435 + self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) # block 432 + self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) # block 433 + self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) # block 434 + self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) # block 435 self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork") txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) - tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']}) + tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']}) assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data assert(tmpl['weightlimit'] == 4000000) assert(tmpl['sigoplimit'] == 80000) assert(tmpl['transactions'][0]['txid'] == txid) assert(tmpl['transactions'][0]['sigops'] == 8) - self.nodes[0].generate(1) # Mine a block to clear the gbt cache + self.nodes[0].generate(1) # Mine a block to clear the gbt cache self.log.info("Non-segwit miners are able to use GBT response after activation.") # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) -> @@ -222,7 +220,7 @@ def run_test(self): txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996")) hex_tx = self.nodes[0].gettransaction(txid)['hex'] tx = FromHex(CTransaction(), hex_tx) - assert(tx.wit.is_null()) # This should not be a segwit input + assert(tx.wit.is_null()) # This should not be a segwit input assert(txid1 in self.nodes[0].getrawmempool()) # Now create tx2, which will spend from txid1. @@ -247,13 +245,13 @@ def run_test(self): template = self.nodes[0].getblocktemplate() # Check that tx1 is the only transaction of the 3 in the template. - template_txids = [ t['txid'] for t in template['transactions'] ] + template_txids = [t['txid'] for t in template['transactions']] assert(txid2 not in template_txids and txid3 not in template_txids) assert(txid1 in template_txids) # Check that running with segwit support results in all 3 being included. template = self.nodes[0].getblocktemplate({"rules": ["segwit"]}) - template_txids = [ t['txid'] for t in template['transactions'] ] + template_txids = [t['txid'] for t in template['transactions']] assert(txid1 in template_txids) assert(txid2 in template_txids) assert(txid3 in template_txids) @@ -268,13 +266,13 @@ def run_test(self): # Some public keys to be used later pubkeys = [ - "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb - "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97 - "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV - "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd - "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66 - "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K - "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ + "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb + "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97 + "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV + "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd + "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66 + "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K + "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ ] # Import a compressed key and an uncompressed key, generate some multisig addresses @@ -282,8 +280,8 @@ def run_test(self): uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"] self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR") compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"] - assert ((self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed'] == False)) - assert ((self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed'] == True)) + assert not self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed'] + assert self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed'] self.nodes[0].importpubkey(pubkeys[0]) compressed_solvable_address = [key_to_p2pkh(pubkeys[0])] @@ -394,9 +392,9 @@ def run_test(self): p2wshop1 = CScript([OP_0, sha256(op1)]) unsolvable_after_importaddress.append(unsolvablep2pkh) unsolvable_after_importaddress.append(unsolvablep2wshp2pkh) - unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script + unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script unsolvable_after_importaddress.append(p2wshop1) - unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided + unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided unsolvable_after_importaddress.append(p2shop0) spendable_txid = [] @@ -432,8 +430,8 @@ def run_test(self): # exceptions and continue. try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True) - self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only - self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey + self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only + self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2)) solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1)) @@ -471,7 +469,7 @@ def run_test(self): uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])] spendable_after_addwitnessaddress = [] # These outputs should be seen after importaddress - solvable_after_addwitnessaddress=[] # These outputs should be seen after importaddress but not spendable + solvable_after_addwitnessaddress = [] # These outputs should be seen after importaddress but not spendable unseen_anytime = [] # These outputs should never be seen solvable_anytime = [] # These outputs should be solvable after importpubkey unseen_anytime = [] # These outputs should never be seen @@ -532,7 +530,7 @@ def run_test(self): # after importaddress it should pass addwitnessaddress v = self.nodes[0].getaddressinfo(compressed_solvable_address[1]) - self.nodes[0].importaddress(v['hex'],"",False,True) + self.nodes[0].importaddress(v['hex'], "", False, True) for i in compressed_spendable_address + compressed_solvable_address + premature_witaddress: witaddress = self.nodes[0].addwitnessaddress(i) assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress)) @@ -542,8 +540,8 @@ def run_test(self): self.mine_and_test_listunspent(unseen_anytime, 0) # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works - v1_addr = program_to_witness(1, [3,5]) - v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])],{v1_addr: 1}) + v1_addr = program_to_witness(1, [3, 5]) + v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1}) v1_decoded = self.nodes[1].decoderawtransaction(v1_tx) assert_equal(v1_decoded['vout'][0]['scriptPubKey']['addresses'][0], v1_addr) assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305") @@ -586,7 +584,7 @@ def run_test(self): def mine_and_test_listunspent(self, script_list, ismine): utxo = find_spendable_utxo(self.nodes[0], 50) tx = CTransaction() - tx.vin.append(CTxIn(COutPoint(int('0x'+utxo['txid'],0), utxo['vout']))) + tx.vin.append(CTxIn(COutPoint(int('0x' + utxo['txid'], 0), utxo['vout']))) for i in script_list: tx.vout.append(CTxOut(10000000, i)) tx.rehash() @@ -599,7 +597,7 @@ def mine_and_test_listunspent(self, script_list, ismine): for i in self.nodes[0].listunspent(): if (i['txid'] == txid): watchcount += 1 - if (i['spendable'] == True): + if i['spendable']: spendcount += 1 if (ismine == 2): assert_equal(spendcount, len(script_list)) @@ -610,14 +608,14 @@ def mine_and_test_listunspent(self, script_list, ismine): assert_equal(watchcount, 0) return txid - def p2sh_address_to_script(self,v): + def p2sh_address_to_script(self, v): bare = CScript(hex_str_to_bytes(v['hex'])) p2sh = CScript(hex_str_to_bytes(v['scriptPubKey'])) p2wsh = CScript([OP_0, sha256(bare)]) p2sh_p2wsh = CScript([OP_HASH160, hash160(p2wsh), OP_EQUAL]) return([bare, p2sh, p2wsh, p2sh_p2wsh]) - def p2pkh_address_to_script(self,v): + def p2pkh_address_to_script(self, v): pubkey = hex_str_to_bytes(v['pubkey']) p2wpkh = CScript([OP_0, hash160(pubkey)]) p2sh_p2wpkh = CScript([OP_HASH160, hash160(p2wpkh), OP_EQUAL]) @@ -631,7 +629,7 @@ def p2pkh_address_to_script(self,v): p2sh_p2wsh_p2pkh = CScript([OP_HASH160, hash160(p2wsh_p2pkh), OP_EQUAL]) return [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] - def create_and_mine_tx_from_txids(self, txids, success = True): + def create_and_mine_tx_from_txids(self, txids, success=True): tx = CTransaction() for i in txids: txtmp = CTransaction() @@ -639,7 +637,7 @@ def create_and_mine_tx_from_txids(self, txids, success = True): f = BytesIO(hex_str_to_bytes(txraw)) txtmp.deserialize(f) for j in range(len(txtmp.vout)): - tx.vin.append(CTxIn(COutPoint(int('0x'+i,0), j))) + tx.vin.append(CTxIn(COutPoint(int('0x' + i, 0), j))) tx.vout.append(CTxOut(0, CScript())) tx.rehash() signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex'] diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 3a5bdf806b..600b97cd11 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -7,7 +7,6 @@ Version 1 compact blocks are pre-segwit (txids) Version 2 compact blocks are post-segwit (wtxids) """ - from decimal import Decimal import random @@ -189,7 +188,7 @@ def check_announcement_of_new_block(node, peer, predicate): # Now try a SENDCMPCT message with too-high version sendcmpct = msg_sendcmpct() - sendcmpct.version = preferred_version+1 + sendcmpct.version = preferred_version + 1 sendcmpct.announce = True test_node.send_and_ping(sendcmpct) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message) @@ -220,7 +219,7 @@ def check_announcement_of_new_block(node, peer, predicate): check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message) # Try one more time, after sending a version-1, announce=false message. - sendcmpct.version = preferred_version-1 + sendcmpct.version = preferred_version - 1 sendcmpct.announce = False test_node.send_and_ping(sendcmpct) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message) @@ -234,7 +233,7 @@ def check_announcement_of_new_block(node, peer, predicate): if old_node is not None: # Verify that a peer using an older protocol version can receive # announcements from this node. - sendcmpct.version = preferred_version-1 + sendcmpct.version = preferred_version - 1 sendcmpct.announce = True old_node.send_and_ping(sendcmpct) # Header sync @@ -267,7 +266,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a # a witness address. address = node.addwitnessaddress(address) value_to_send = node.getbalance() - node.sendtoaddress(address, satoshi_round(value_to_send-Decimal(0.1))) + node.sendtoaddress(address, satoshi_round(value_to_send - Decimal(0.1))) node.generate(1) segwit_tx_generated = False @@ -279,7 +278,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a segwit_tx_generated = True if use_witness_address: - assert(segwit_tx_generated) # check that our test is not broken + assert segwit_tx_generated # check that our test is not broken # Wait until we've seen the block announcement for the resulting tip tip = int(node.getbestblockhash(), 16) @@ -403,8 +402,7 @@ def test_compactblock_requests(self, node, test_node, version, segwit): coinbase_hash = block.vtx[0].sha256 if version == 2: coinbase_hash = block.vtx[0].calc_sha256(True) - comp_block.shortids = [ - calculate_shortid(k0, k1, coinbase_hash) ] + comp_block.shortids = [calculate_shortid(k0, k1, coinbase_hash)] test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) # Expect a getblocktxn message. @@ -443,7 +441,7 @@ def build_block_with_transactions(self, node, utxo, num_transactions): # node needs, and that responding to them causes the block to be # reconstructed. def test_getblocktxn_requests(self, node, test_node, version): - with_witness = (version==2) + with_witness = (version == 2) def test_getblocktxn_response(compact_block, peer, expected_result): msg = msg_cmpctblock(compact_block.to_p2p()) @@ -470,7 +468,7 @@ def test_tip_after_message(node, peer, msg, tip): msg_bt = msg_blocktxn() if with_witness: - msg_bt = msg_witness_blocktxn() # serialize with witnesses + msg_bt = msg_witness_blocktxn() # serialize with witnesses msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[1:]) test_tip_after_message(node, test_node, msg_bt, block.sha256) @@ -560,7 +558,7 @@ def test_incorrect_blocktxn_response(self, node, test_node, version): # verifying that the block isn't marked bad permanently. This is good # enough for now. msg = msg_blocktxn() - if version==2: + if version == 2: msg = msg_witness_blocktxn() msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:]) test_node.send_and_ping(msg) @@ -571,11 +569,11 @@ def test_incorrect_blocktxn_response(self, node, test_node, version): # We should receive a getdata request wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock) assert_equal(len(test_node.last_message["getdata"].inv), 1) - assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG) + assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2 | MSG_WITNESS_FLAG) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) # Deliver the block - if version==2: + if version == 2: test_node.send_and_ping(msg_witness_block(block)) else: test_node.send_and_ping(msg_block(block)) @@ -655,7 +653,7 @@ def test_compactblocks_not_at_tip(self, node, test_node): # Generate an old compactblock, and verify that it's not accepted. cur_height = node.getblockcount() - hashPrevBlock = int(node.getblockhash(cur_height-5), 16) + hashPrevBlock = int(node.getblockhash(cur_height - 5), 16) block = self.build_block_on_tip(node) block.hashPrevBlock = hashPrevBlock block.solve() @@ -684,7 +682,7 @@ def test_compactblocks_not_at_tip(self, node, test_node): assert "blocktxn" not in test_node.last_message def activate_segwit(self, node): - node.generate(144*3) + node.generate(144 * 3) assert_equal(get_bip9_status(node, "segwit")["status"], 'active') def test_end_to_end_block_relay(self, node, listeners): @@ -780,7 +778,7 @@ def announce_cmpct_block(node, peer): delivery_peer.send_message(msg_tx(tx)) delivery_peer.sync_with_ping() - cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [ CTxInWitness() ] + cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()] cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)] cmpct_block.use_witness = True @@ -886,7 +884,7 @@ def run_test(self): self.log.info("Syncing nodes...") assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash()) while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()): - block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount()+1) + block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount() + 1) self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False)) assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash()) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 67ee00871d..b4580ac74a 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -13,20 +13,17 @@ added in the future, they should try to follow the same convention and not make assumptions about execution order. """ - from decimal import Decimal +import io from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes, sync_mempools -import io - WALLET_PASSPHRASE = "test" WALLET_PASSPHRASE_TIMEOUT = 3600 - class BumpFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 @@ -157,7 +154,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): signedtx = peer_node.signrawtransactionwithwallet(signedtx["hex"]) rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) assert_raises_rpc_error(-4, "Transaction contains inputs that don't belong to this wallet", - rbf_node.bumpfee, rbfid) + rbf_node.bumpfee, rbfid) def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address): @@ -187,11 +184,11 @@ def test_dust_to_fee(rbf_node, dest_address): # (32-byte p2sh-pwpkh output size + 148 p2pkh spend estimate) * 10k(discard_rate) / 1000 = 1800 # P2SH outputs are slightly "over-discarding" due to the IsDust calculation assuming it will # be spent as a P2PKH. - bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 50000-1800}) + bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 50000 - 1800}) full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1) assert_equal(bumped_tx["fee"], Decimal("0.00050000")) assert_equal(len(fulltx["vout"]), 2) - assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated + assert_equal(len(full_bumped_tx["vout"]), 1) # change output is eliminated def test_settxfee(rbf_node, dest_address): @@ -222,7 +219,7 @@ def test_rebumping_not_replaceable(rbf_node, dest_address): rbfid = spend_one_input(rbf_node, dest_address) bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False}) assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], - {"totalFee": 20000}) + {"totalFee": 20000}) def test_unconfirmed_not_spendable(rbf_node, rbf_node_address): @@ -276,7 +273,7 @@ def test_locked_wallet_fails(rbf_node, dest_address): rbfid = spend_one_input(rbf_node, dest_address) rbf_node.walletlock() assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.", - rbf_node.bumpfee, rbfid) + rbf_node.bumpfee, rbfid) def spend_one_input(node, dest_address): diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index b1db1e4ab9..643289a8c7 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -3,7 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the dumpwallet RPC.""" - import os from test_framework.test_framework import BitcoinTestFramework @@ -107,9 +106,9 @@ def run_test(self): # wallet, we will expect 21 addresses in the dump test_addr_count = 20 addrs = [] - for i in range(0,test_addr_count): + for i in range(0, test_addr_count): addr = self.nodes[0].getnewaddress() - vaddr= self.nodes[0].getaddressinfo(addr) #required to get hd keypath + vaddr = self.nodes[0].getaddressinfo(addr) # required to get hd keypath addrs.append(vaddr) # Should be a no-op: self.nodes[0].keypoolrefill() @@ -131,7 +130,7 @@ def run_test(self): assert_equal(found_addr_rsv, 90 * 2) # 90 keys plus 100% internal keys assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key - #encrypt wallet, restart, unlock and dump + # encrypt wallet, restart, unlock and dump self.nodes[0].encryptwallet('test') self.nodes[0].walletpassphrase('test', 10) # Should be a no-op: @@ -155,13 +154,13 @@ def run_test(self): # Make sure the address is not IsMine before import result = self.nodes[0].getaddressinfo(multisig_addr) - assert(result['ismine'] == False) + assert not result['ismine'] self.nodes[0].importwallet(wallet_unenc_dump) # Now check IsMine is true result = self.nodes[0].getaddressinfo(multisig_addr) - assert(result['ismine'] == True) + assert result['ismine'] if __name__ == '__main__': WalletDumpTest().main() From bdefc9705d7ea5ba3c0e9b7048c4181f43d8be46 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 15:32:53 -0400 Subject: [PATCH 038/263] [tests] Remove deprecated addwitnessaddress call from feature_nulldummy addwitnessaddress is deprecated. Replace the call to addwitnessaddress with a call to getnewaddress(address_type='p2sh-segwit') --- test/functional/feature_nulldummy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index f51d5ca4fe..eb76089d9c 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -41,7 +41,7 @@ def set_test_params(self): self.setup_clean_chain = True # This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through # normal segwit activation here (and don't use the default always-on behaviour). - self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy', "-deprecatedrpc=addwitnessaddress"]] + self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy']] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -49,7 +49,7 @@ def skip_test_if_missing_module(self): def run_test(self): self.address = self.nodes[0].getnewaddress() self.ms_address = self.nodes[0].addmultisigaddress(1, [self.address])['address'] - self.wit_address = self.nodes[0].addwitnessaddress(self.address) + self.wit_address = self.nodes[0].getnewaddress(address_type='p2sh-segwit') self.wit_ms_address = self.nodes[0].addmultisigaddress(1, [self.address], '', 'p2sh-segwit')['address'] self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 From 3cf77f0b3ee0862e87c98db5363b4da83f9089e0 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 15:34:25 -0400 Subject: [PATCH 039/263] [tests] Remove deprecated addwitnessaddress call from wallet_dump.py addwitnessaddress is deprecated. Remove the call to that RPC from wallet_dump.py and improve testing of all types of address (legacy, p2sh-segwit and bech32) --- test/functional/wallet_dump.py | 76 ++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 643289a8c7..20cb816ee8 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -18,11 +18,12 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): Also check that the old hd_master is inactive """ with open(file_name, encoding='utf8') as inputfile: - found_addr = 0 + found_legacy_addr = 0 + found_p2sh_segwit_addr = 0 + found_bech32_addr = 0 found_script_addr = 0 found_addr_chg = 0 found_addr_rsv = 0 - witness_addr_ret = None hd_master_addr_ret = None for line in inputfile: # only read non comment lines @@ -59,14 +60,14 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): # count key types for addrObj in addrs: if addrObj['address'] == addr.split(",")[0] and addrObj['hdkeypath'] == keypath and keytype == "label=": - # a labeled entry in the wallet should contain both a native address - # and the p2sh-p2wpkh address that was added at wallet setup - if len(addr.split(",")) == 2: - addr_list = addr.split(",") - # the entry should be of the first key in the wallet - assert_equal(addrs[0]['address'], addr_list[0]) - witness_addr_ret = addr_list[1] - found_addr += 1 + if addr.startswith('m') or addr.startswith('n'): + # P2PKH address + found_legacy_addr += 1 + elif addr.startswith('2'): + # P2SH-segwit address + found_p2sh_segwit_addr += 1 + elif addr.startswith('bcrt1'): + found_bech32_addr += 1 break elif keytype == "change=1": found_addr_chg += 1 @@ -81,13 +82,13 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): found_script_addr += 1 break - return found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret, witness_addr_ret + return found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret class WalletDumpTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [["-keypool=90", "-addresstype=legacy", "-deprecatedrpc=addwitnessaddress"]] + self.extra_args = [["-keypool=90", "-addresstype=legacy"]] self.rpc_timeout = 120 def skip_test_if_missing_module(self): @@ -101,34 +102,38 @@ def run_test(self): wallet_unenc_dump = os.path.join(self.nodes[0].datadir, "wallet.unencrypted.dump") wallet_enc_dump = os.path.join(self.nodes[0].datadir, "wallet.encrypted.dump") - # generate 20 addresses to compare against the dump - # but since we add a p2sh-p2wpkh address for the first pubkey in the - # wallet, we will expect 21 addresses in the dump - test_addr_count = 20 + # generate 30 addresses to compare against the dump + # - 10 legacy P2PKH + # - 10 P2SH-segwit + # - 10 bech32 + test_addr_count = 10 addrs = [] - for i in range(0, test_addr_count): - addr = self.nodes[0].getnewaddress() - vaddr = self.nodes[0].getaddressinfo(addr) # required to get hd keypath - addrs.append(vaddr) - # Should be a no-op: - self.nodes[0].keypoolrefill() + for address_type in ['legacy', 'p2sh-segwit', 'bech32']: + for i in range(0, test_addr_count): + addr = self.nodes[0].getnewaddress(address_type=address_type) + vaddr = self.nodes[0].getaddressinfo(addr) # required to get hd keypath + addrs.append(vaddr) - # Test scripts dump by adding a P2SH witness and a 1-of-1 multisig address - witness_addr = self.nodes[0].addwitnessaddress(addrs[0]["address"], True) + # Test scripts dump by adding a 1-of-1 multisig address multisig_addr = self.nodes[0].addmultisigaddress(1, [addrs[1]["address"]])["address"] - script_addrs = [witness_addr, multisig_addr] + + # Refill the keypool. getnewaddress() refills the keypool *before* taking a key from + # the keypool, so the final call to getnewaddress leaves the keypool with one key below + # its capacity + self.nodes[0].keypoolrefill() # dump unencrypted wallet result = self.nodes[0].dumpwallet(wallet_unenc_dump) assert_equal(result['filename'], wallet_unenc_dump) - found_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc, witness_addr_ret = \ - read_dump(wallet_unenc_dump, addrs, script_addrs, None) - assert_equal(found_addr, test_addr_count) # all keys must be in the dump - assert_equal(found_script_addr, 2) # all scripts must be in the dump + found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \ + read_dump(wallet_unenc_dump, addrs, [multisig_addr], None) + assert_equal(found_legacy_addr, test_addr_count) # all keys must be in the dump + assert_equal(found_p2sh_segwit_addr, test_addr_count) # all keys must be in the dump + assert_equal(found_bech32_addr, test_addr_count) # all keys must be in the dump + assert_equal(found_script_addr, 1) # all scripts must be in the dump assert_equal(found_addr_chg, 0) # 0 blocks where mined assert_equal(found_addr_rsv, 90 * 2) # 90 keys plus 100% internal keys - assert_equal(witness_addr_ret, witness_addr) # p2sh-p2wsh address added to the first key # encrypt wallet, restart, unlock and dump self.nodes[0].encryptwallet('test') @@ -137,13 +142,14 @@ def run_test(self): self.nodes[0].keypoolrefill() self.nodes[0].dumpwallet(wallet_enc_dump) - found_addr, found_script_addr, found_addr_chg, found_addr_rsv, _, witness_addr_ret = \ - read_dump(wallet_enc_dump, addrs, script_addrs, hd_master_addr_unenc) - assert_equal(found_addr, test_addr_count) - assert_equal(found_script_addr, 2) + found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, _ = \ + read_dump(wallet_enc_dump, addrs, [multisig_addr], hd_master_addr_unenc) + assert_equal(found_legacy_addr, test_addr_count) # all keys must be in the dump + assert_equal(found_p2sh_segwit_addr, test_addr_count) # all keys must be in the dump + assert_equal(found_bech32_addr, test_addr_count) # all keys must be in the dump + assert_equal(found_script_addr, 1) assert_equal(found_addr_chg, 90 * 2) # old reserve keys are marked as change now assert_equal(found_addr_rsv, 90 * 2) - assert_equal(witness_addr_ret, witness_addr) # Overwriting should fail assert_raises_rpc_error(-8, "already exists", lambda: self.nodes[0].dumpwallet(wallet_enc_dump)) From 9d7ee187a3ceb9270af316ae3eb8f2de27d70b1f Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 22:57:40 -0400 Subject: [PATCH 040/263] [test] Remove deprecated addwitnessaddress from p2p_compactblocks.py --- test/functional/p2p_compactblocks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 600b97cd11..04353ae96f 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -98,7 +98,7 @@ def set_test_params(self): self.num_nodes = 2 # This test was written assuming SegWit is activated using BIP9 at height 432 (3x confirmation window). # TODO: Rewrite this test to support SegWit being always active. - self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex", "-deprecatedrpc=addwitnessaddress"]] + self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex"]] self.utxos = [] def skip_test_if_missing_module(self): @@ -264,7 +264,7 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a if use_witness_address: # Want at least one segwit spend, so move all funds to # a witness address. - address = node.addwitnessaddress(address) + address = node.getnewaddress(address_type='bech32') value_to_send = node.getbalance() node.sendtoaddress(address, satoshi_round(value_to_send - Decimal(0.1))) node.generate(1) From 82f2fa03a58df7418f88f176e94c3aa70d7a6c64 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 23:01:32 -0400 Subject: [PATCH 041/263] [test] Remove deprecated addwitnessaddress from wallet_bumpfee.py --- test/functional/wallet_bumpfee.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index b4580ac74a..7d3d9b61e2 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -29,7 +29,6 @@ def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True self.extra_args = [[ - "-deprecatedrpc=addwitnessaddress", "-walletrbf={}".format(i), "-mintxfee=0.00002", ] for i in range(self.num_nodes)] @@ -104,8 +103,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address): # which spends it, and make sure bumpfee can be called on it. segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001")) - segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress()) - rbf_node.addwitnessaddress(segwit_out["address"]) + segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress(address_type='p2sh-segwit')) segwitid = send_to_witness( use_p2wsh=False, node=rbf_node, From 07e3f585abcee10c0283f2bd2f50eaa953df4d41 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 23:15:49 -0400 Subject: [PATCH 042/263] [test] Remove deprecated addwitnessaddress from feature_segwit.py --- test/functional/feature_segwit.py | 50 +------------------------------ 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index fcf175cb2e..7098a03f1e 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -9,8 +9,6 @@ from test_framework.address import ( key_to_p2pkh, - key_to_p2sh_p2wpkh, - key_to_p2wpkh, program_to_witness, script_to_p2sh, script_to_p2sh_p2wsh, @@ -50,20 +48,17 @@ def set_test_params(self): "-rpcserialversion=0", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", - "-deprecatedrpc=addwitnessaddress", ], [ "-blockversion=4", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", - "-deprecatedrpc=addwitnessaddress", ], [ "-blockversion=536870915", "-vbparams=segwit:0:999999999999", "-addresstype=legacy", - "-deprecatedrpc=addwitnessaddress", ], ] @@ -117,12 +112,8 @@ def run_test(self): newaddress = self.nodes[i].getnewaddress() self.pubkey.append(self.nodes[i].getaddressinfo(newaddress)["pubkey"]) multiscript = CScript([OP_1, hex_str_to_bytes(self.pubkey[-1]), OP_1, OP_CHECKMULTISIG]) - p2sh_addr = self.nodes[i].addwitnessaddress(newaddress) - bip173_addr = self.nodes[i].addwitnessaddress(newaddress, False) p2sh_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'p2sh-segwit')['address'] bip173_ms_addr = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]], '', 'bech32')['address'] - assert_equal(p2sh_addr, key_to_p2sh_p2wpkh(self.pubkey[-1])) - assert_equal(bip173_addr, key_to_p2wpkh(self.pubkey[-1])) assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript)) assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript)) p2sh_ids.append([]) @@ -262,7 +253,7 @@ def run_test(self): # Mine a block to clear the gbt cache again. self.nodes[0].generate(1) - self.log.info("Verify behaviour of importaddress, addwitnessaddress and listunspent") + self.log.info("Verify behaviour of importaddress and listunspent") # Some public keys to be used later pubkeys = [ @@ -303,7 +294,6 @@ def run_test(self): uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])['address']) compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address']) compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])['address']) - unknown_address = ["mtKKyoHabkk6e4ppT7NaM7THqPUt7AzPrT", "2NDP3jLWAFT8NDAiUa9qiE6oBt2awmMq7Dx"] # Test multisig_without_privkey # We have 2 public keys without private keys, use addmultisigaddress to add to wallet. @@ -384,7 +374,6 @@ def run_test(self): op1 = CScript([OP_1]) op0 = CScript([OP_0]) # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V - unsolvable_address = ["mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V", "2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe", script_to_p2sh(op1), script_to_p2sh(op0)] unsolvable_address_key = hex_str_to_bytes("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D") unsolvablep2pkh = CScript([OP_DUP, OP_HASH160, hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG]) unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)]) @@ -438,19 +427,6 @@ def run_test(self): self.mine_and_test_listunspent(unsolvable_after_importaddress, 1) self.mine_and_test_listunspent(unseen_anytime, 0) - # addwitnessaddress should refuse to return a witness address if an uncompressed key is used - # note that no witness address should be returned by unsolvable addresses - for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address: - assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) - - # addwitnessaddress should return a witness addresses even if keys are not in the wallet - self.nodes[0].addwitnessaddress(multisig_without_privkey_address) - - for i in compressed_spendable_address + compressed_solvable_address: - witaddress = self.nodes[0].addwitnessaddress(i) - # addwitnessaddress should return the same address if it is a known P2SH-witness address - assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress)) - spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2)) solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1)) self.mine_and_test_listunspent(unsolvable_after_importaddress, 1) @@ -468,8 +444,6 @@ def run_test(self): self.nodes[0].importpubkey(pubkeys[6]) uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])] - spendable_after_addwitnessaddress = [] # These outputs should be seen after importaddress - solvable_after_addwitnessaddress = [] # These outputs should be seen after importaddress but not spendable unseen_anytime = [] # These outputs should never be seen solvable_anytime = [] # These outputs should be solvable after importpubkey unseen_anytime = [] # These outputs should never be seen @@ -486,8 +460,6 @@ def run_test(self): v = self.nodes[0].getaddressinfo(i) if (v['isscript']): [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) - # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after addwitnessaddress - spendable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh]) premature_witaddress.append(script_to_p2sh(p2wsh)) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) @@ -508,9 +480,7 @@ def run_test(self): for i in compressed_solvable_address: v = self.nodes[0].getaddressinfo(i) if (v['isscript']): - # P2WSH multisig without private key are seen after addwitnessaddress [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) - solvable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh]) premature_witaddress.append(script_to_p2sh(p2wsh)) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) @@ -519,24 +489,6 @@ def run_test(self): self.mine_and_test_listunspent(spendable_anytime, 2) self.mine_and_test_listunspent(solvable_anytime, 1) - self.mine_and_test_listunspent(spendable_after_addwitnessaddress + solvable_after_addwitnessaddress + unseen_anytime, 0) - - # addwitnessaddress should refuse to return a witness address if an uncompressed key is used - # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress - # premature_witaddress are not accepted until the script is added with addwitnessaddress first - for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress: - # This will raise an exception - assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) - - # after importaddress it should pass addwitnessaddress - v = self.nodes[0].getaddressinfo(compressed_solvable_address[1]) - self.nodes[0].importaddress(v['hex'], "", False, True) - for i in compressed_spendable_address + compressed_solvable_address + premature_witaddress: - witaddress = self.nodes[0].addwitnessaddress(i) - assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress)) - - spendable_txid.append(self.mine_and_test_listunspent(spendable_after_addwitnessaddress + spendable_anytime, 2)) - solvable_txid.append(self.mine_and_test_listunspent(solvable_after_addwitnessaddress + solvable_anytime, 1)) self.mine_and_test_listunspent(unseen_anytime, 0) # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works From ebec90ac9731f8955d120a5d8419948d500b31c9 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 22 Sep 2018 23:19:57 -0400 Subject: [PATCH 043/263] [wallet] Remove deprecated addwitnessaddress RPC method --- src/rpc/client.cpp | 1 - src/wallet/rpcwallet.cpp | 126 --------------------------------------- 2 files changed, 127 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 649e222c39..c6570625ca 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -148,7 +148,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "logging", 0, "include" }, { "logging", 1, "exclude" }, { "disconnectnode", 1, "nodeid" }, - { "addwitnessaddress", 1, "p2sh" }, // Echo with conversion (For testing only) { "echojson", 0, "arg0" }, { "echojson", 1, "arg1" }, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1a2dff9a96..a36bad4512 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -982,131 +982,6 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) return result; } -class Witnessifier : public boost::static_visitor -{ -public: - CWallet * const pwallet; - CTxDestination result; - bool already_witness; - - explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {} - - bool operator()(const CKeyID &keyID) { - if (pwallet) { - CScript basescript = GetScriptForDestination(keyID); - CScript witscript = GetScriptForWitness(basescript); - if (!IsSolvable(*pwallet, witscript)) { - return false; - } - return ExtractDestination(witscript, result); - } - return false; - } - - bool operator()(const CScriptID &scriptID) { - CScript subscript; - if (pwallet && pwallet->GetCScript(scriptID, subscript)) { - int witnessversion; - std::vector witprog; - if (subscript.IsWitnessProgram(witnessversion, witprog)) { - ExtractDestination(subscript, result); - already_witness = true; - return true; - } - CScript witscript = GetScriptForWitness(subscript); - if (!IsSolvable(*pwallet, witscript)) { - return false; - } - return ExtractDestination(witscript, result); - } - return false; - } - - bool operator()(const WitnessV0KeyHash& id) - { - already_witness = true; - result = id; - return true; - } - - bool operator()(const WitnessV0ScriptHash& id) - { - already_witness = true; - result = id; - return true; - } - - template - bool operator()(const T& dest) { return false; } -}; - -static UniValue addwitnessaddress(const JSONRPCRequest& request) -{ - std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - CWallet* const pwallet = wallet.get(); - - if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { - return NullUniValue; - } - - if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - { - std::string msg = "addwitnessaddress \"address\" ( p2sh )\n" - "\nDEPRECATED: set the address_type argument of getnewaddress, or option -addresstype=[bech32|p2sh-segwit] instead.\n" - "Add a witness address for a script (with pubkey or redeemscript known). Requires a new wallet backup.\n" - "It returns the witness script.\n" - - "\nArguments:\n" - "1. \"address\" (string, required) An address known to the wallet\n" - "2. p2sh (bool, optional, default=true) Embed inside P2SH\n" - - "\nResult:\n" - "\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n" - "}\n" - ; - throw std::runtime_error(msg); - } - - if (!IsDeprecatedRPCEnabled("addwitnessaddress")) { - throw JSONRPCError(RPC_METHOD_DEPRECATED, "addwitnessaddress is deprecated and will be fully removed in v0.17. " - "To use addwitnessaddress in v0.16, restart bitcoind with -deprecatedrpc=addwitnessaddress.\n" - "Projects should transition to using the address_type argument of getnewaddress, or option -addresstype=[bech32|p2sh-segwit] instead.\n"); - } - - CTxDestination dest = DecodeDestination(request.params[0].get_str()); - if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - } - - bool p2sh = true; - if (!request.params[1].isNull()) { - p2sh = request.params[1].get_bool(); - } - - Witnessifier w(pwallet); - bool ret = boost::apply_visitor(w, dest); - if (!ret) { - throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed"); - } - - CScript witprogram = GetScriptForDestination(w.result); - - if (p2sh) { - w.result = CScriptID(witprogram); - } - - if (w.already_witness) { - if (!(dest == w.result)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types"); - } - } else { - pwallet->AddCScript(witprogram); // Implicit for single-key now, but necessary for multisig and for compatibility with older software - pwallet->SetAddressBook(w.result, "", "receive"); - } - - return EncodeDestination(w.result); -} - struct tallyitem { CAmount nAmount; @@ -4065,7 +3940,6 @@ static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- { "generating", "generate", &generate, {"nblocks","maxtries"} }, - { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} }, { "hidden", "resendwallettransactions", &resendwallettransactions, {} }, { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, From 30973e9844d9ed8f2932ad7088cae39c49f3ebb5 Mon Sep 17 00:00:00 2001 From: Antoine Le Calvez Date: Sun, 23 Sep 2018 14:12:42 +0100 Subject: [PATCH 044/263] [REST] improve performance for JSON calls JSON calls do not use the raw data generated for the .bin and .hex calls. By moving the raw data creation into the .bin and .hex switch branches, JSON calls become faster. --- src/rest.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/rest.cpp b/src/rest.cpp index 6ba15172fa..7792844992 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -157,13 +157,13 @@ static bool rest_headers(HTTPRequest* req, } } - CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); - for (const CBlockIndex *pindex : headers) { - ssHeader << pindex->GetBlockHeader(); - } - switch (rf) { case RetFormat::BINARY: { + CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); + for (const CBlockIndex *pindex : headers) { + ssHeader << pindex->GetBlockHeader(); + } + std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryHeader); @@ -171,6 +171,11 @@ static bool rest_headers(HTTPRequest* req, } case RetFormat::HEX: { + CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); + for (const CBlockIndex *pindex : headers) { + ssHeader << pindex->GetBlockHeader(); + } + std::string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); @@ -224,11 +229,10 @@ static bool rest_block(HTTPRequest* req, return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); - ssBlock << block; - switch (rf) { case RetFormat::BINARY: { + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); + ssBlock << block; std::string binaryBlock = ssBlock.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryBlock); @@ -236,6 +240,8 @@ static bool rest_block(HTTPRequest* req, } case RetFormat::HEX: { + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); + ssBlock << block; std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); @@ -360,11 +366,11 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); - ssTx << tx; - switch (rf) { case RetFormat::BINARY: { + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); + ssTx << tx; + std::string binaryTx = ssTx.str(); req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteReply(HTTP_OK, binaryTx); @@ -372,6 +378,9 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) } case RetFormat::HEX: { + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); + ssTx << tx; + std::string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); req->WriteReply(HTTP_OK, strHex); From ba923e32a0c03fcbb6ffe317580fd1d04669ce71 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sun, 23 Sep 2018 20:44:15 +0200 Subject: [PATCH 045/263] test: Fix broken segwit test --- test/functional/p2p_segwit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index de12ab1ed6..58bfd1c942 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -771,8 +771,8 @@ def test_p2sh_witness(self): # segwit-aware would also reject this for failing CLEANSTACK. test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) - # Try to put the witness script in the script_sig, should also fail. - spend_tx.vin[0].script_sig = CScript([p2wsh_pubkey, b'a']) + # Try to put the witness script in the scriptSig, should also fail. + spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a']) spend_tx.rehash() test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) From 980b38f8a12130d2761d0f748db750165cfed025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Sat, 16 Jun 2018 22:33:42 +0200 Subject: [PATCH 046/263] MOVEONLY: Move versionbits info out of versionbits.o --- src/Makefile.am | 2 ++ src/init.cpp | 1 + src/rpc/blockchain.cpp | 1 + src/rpc/mining.cpp | 1 + src/versionbits.cpp | 15 --------------- src/versionbits.h | 9 --------- src/versionbitsinfo.cpp | 22 ++++++++++++++++++++++ src/versionbitsinfo.h | 17 +++++++++++++++++ 8 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 src/versionbitsinfo.cpp create mode 100644 src/versionbitsinfo.h diff --git a/src/Makefile.am b/src/Makefile.am index f7d7a5d377..a1b9b4cb82 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -187,6 +187,7 @@ BITCOIN_CORE_H = \ validation.h \ validationinterface.h \ versionbits.h \ + versionbitsinfo.h \ walletinitinterface.h \ wallet/coincontrol.h \ wallet/crypter.h \ @@ -400,6 +401,7 @@ libbitcoin_common_a_SOURCES = \ script/ismine.cpp \ script/sign.cpp \ script/standard.cpp \ + versionbitsinfo.cpp \ warnings.cpp \ $(BITCOIN_CORE_H) diff --git a/src/init.cpp b/src/init.cpp index d10edbd8b6..bb23748d82 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 439427cd7e..073ab8b1b1 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index b1bea85fef..3eac8a1016 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/src/versionbits.cpp b/src/versionbits.cpp index b0d2bc8a14..3f297c0ebb 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -5,21 +5,6 @@ #include #include -const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = { - { - /*.name =*/ "testdummy", - /*.gbt_force =*/ true, - }, - { - /*.name =*/ "csv", - /*.gbt_force =*/ true, - }, - { - /*.name =*/ "segwit", - /*.gbt_force =*/ true, - } -}; - ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const { int nPeriod = Period(params); diff --git a/src/versionbits.h b/src/versionbits.h index e4bf9cb9be..cdc947cd9e 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -30,13 +30,6 @@ enum class ThresholdState { // will either be nullptr or a block with (height + 1) % Period() == 0. typedef std::map ThresholdConditionCache; -struct VBDeploymentInfo { - /** Deployment name */ - const char *name; - /** Whether GBT clients can safely ignore this rule in simplified usage */ - bool gbt_force; -}; - struct BIP9Stats { int period; int threshold; @@ -45,8 +38,6 @@ struct BIP9Stats { bool possible; }; -extern const struct VBDeploymentInfo VersionBitsDeploymentInfo[]; - /** * Abstract class that implements BIP9-style threshold logic, and caches results. */ diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp new file mode 100644 index 0000000000..ecf3482927 --- /dev/null +++ b/src/versionbitsinfo.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2016-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. + +#include + +#include + +const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = { + { + /*.name =*/ "testdummy", + /*.gbt_force =*/ true, + }, + { + /*.name =*/ "csv", + /*.gbt_force =*/ true, + }, + { + /*.name =*/ "segwit", + /*.gbt_force =*/ true, + } +}; diff --git a/src/versionbitsinfo.h b/src/versionbitsinfo.h new file mode 100644 index 0000000000..a7822bc747 --- /dev/null +++ b/src/versionbitsinfo.h @@ -0,0 +1,17 @@ +// Copyright (c) 2016-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. + +#ifndef BITCOIN_VERSIONBITSINFO_H +#define BITCOIN_VERSIONBITSINFO_H + +struct VBDeploymentInfo { + /** Deployment name */ + const char *name; + /** Whether GBT clients can safely ignore this rule in simplified usage */ + bool gbt_force; +}; + +extern const struct VBDeploymentInfo VersionBitsDeploymentInfo[]; + +#endif // BITCOIN_VERSIONBITSINFO_H From 6fa901fb4726ddac025d5396ecf09d047a8aa9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Sat, 16 Jun 2018 22:38:13 +0200 Subject: [PATCH 047/263] Don't edit Chainparams after initialization --- src/chainparams.cpp | 67 ++++++++++++++++++++++++++++++--------- src/chainparams.h | 8 +---- src/chainparamsbase.cpp | 1 + src/init.cpp | 35 -------------------- src/test/test_bitcoin.cpp | 7 ++-- 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b80cc2c259..0574e2395e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -10,9 +10,13 @@ #include #include #include +#include #include +#include +#include + static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { CMutableTransaction txNew; @@ -52,12 +56,6 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward); } -void CChainParams::UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) -{ - consensus.vDeployments[d].nStartTime = nStartTime; - consensus.vDeployments[d].nTimeout = nTimeout; -} - /** * Main network */ @@ -270,7 +268,7 @@ class CTestNetParams : public CChainParams { */ class CRegTestParams : public CChainParams { public: - CRegTestParams() { + explicit CRegTestParams(const ArgsManager& args) { strNetworkID = "regtest"; consensus.nSubsidyHalvingInterval = 150; consensus.BIP16Exception = uint256(); @@ -308,6 +306,8 @@ class CRegTestParams : public CChainParams { nDefaultPort = 18444; nPruneAfterHeight = 1000; + UpdateVersionBitsParametersFromArgs(args); + genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); @@ -343,23 +343,65 @@ class CRegTestParams : public CChainParams { /* enable fallback fee on regtest */ m_fallback_fee_enabled = true; } + + /** + * Allows modifying the Version Bits regtest parameters. + */ + void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) + { + consensus.vDeployments[d].nStartTime = nStartTime; + consensus.vDeployments[d].nTimeout = nTimeout; + } + void UpdateVersionBitsParametersFromArgs(const ArgsManager& args); }; -static std::unique_ptr globalChainParams; +void CRegTestParams::UpdateVersionBitsParametersFromArgs(const ArgsManager& args) +{ + if (!args.IsArgSet("-vbparams")) return; + + for (const std::string& strDeployment : args.GetArgs("-vbparams")) { + std::vector vDeploymentParams; + boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":")); + if (vDeploymentParams.size() != 3) { + throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end"); + } + int64_t nStartTime, nTimeout; + if (!ParseInt64(vDeploymentParams[1], &nStartTime)) { + throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); + } + if (!ParseInt64(vDeploymentParams[2], &nTimeout)) { + throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); + } + bool found = false; + for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { + if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) { + UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout); + found = true; + LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout); + break; + } + } + if (!found) { + throw std::runtime_error(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); + } + } +} + +static std::unique_ptr globalChainParams; const CChainParams &Params() { assert(globalChainParams); return *globalChainParams; } -std::unique_ptr CreateChainParams(const std::string& chain) +std::unique_ptr CreateChainParams(const std::string& chain) { if (chain == CBaseChainParams::MAIN) return std::unique_ptr(new CMainParams()); else if (chain == CBaseChainParams::TESTNET) return std::unique_ptr(new CTestNetParams()); else if (chain == CBaseChainParams::REGTEST) - return std::unique_ptr(new CRegTestParams()); + return std::unique_ptr(new CRegTestParams(gArgs)); throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } @@ -368,8 +410,3 @@ void SelectParams(const std::string& network) SelectBaseParams(network); globalChainParams = CreateChainParams(network); } - -void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout) -{ - globalChainParams->UpdateVersionBitsParameters(d, nStartTime, nTimeout); -} diff --git a/src/chainparams.h b/src/chainparams.h index 722e52ff40..19818b40af 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -80,7 +80,6 @@ class CChainParams const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } const ChainTxData& TxData() const { return chainTxData; } - void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout); protected: CChainParams() {} @@ -107,7 +106,7 @@ class CChainParams * @returns a CChainParams* of the chosen chain. * @throws a std::runtime_error if the chain is not supported. */ -std::unique_ptr CreateChainParams(const std::string& chain); +std::unique_ptr CreateChainParams(const std::string& chain); /** * Return the currently selected parameters. This won't change after app @@ -121,9 +120,4 @@ const CChainParams &Params(); */ void SelectParams(const std::string& chain); -/** - * Allows modifying the Version Bits regtest parameters. - */ -void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout); - #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index e9e8ce03b4..870640e77d 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -20,6 +20,7 @@ void SetupChainParamsBaseOptions() gArgs.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. " "This is intended for regression testing tools and app development.", true, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-testnet", "Use the test chain", false, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", true, OptionsCategory::CHAINPARAMS); } static std::unique_ptr globalChainBaseParams; diff --git a/src/init.cpp b/src/init.cpp index bb23748d82..00d97629f7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -446,7 +445,6 @@ void SetupServerArgs() gArgs.AddArg("-limitancestorsize=", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-limitdescendantcount=", strprintf("Do not accept transactions if any ancestor would have or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-addrmantest", "Allows to test address relay on localhost", true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-debug=", "Output debugging information (default: -nodebug, supplying is optional). " "If is not supplied or if = 1, output all debugging information. can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST); @@ -1102,39 +1100,6 @@ bool AppInitParameterInteraction() fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); } - if (gArgs.IsArgSet("-vbparams")) { - // Allow overriding version bits parameters for testing - if (!chainparams.MineBlocksOnDemand()) { - return InitError("Version bits parameters may only be overridden on regtest."); - } - for (const std::string& strDeployment : gArgs.GetArgs("-vbparams")) { - std::vector vDeploymentParams; - boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":")); - if (vDeploymentParams.size() != 3) { - return InitError("Version bits parameters malformed, expecting deployment:start:end"); - } - int64_t nStartTime, nTimeout; - if (!ParseInt64(vDeploymentParams[1], &nStartTime)) { - return InitError(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1])); - } - if (!ParseInt64(vDeploymentParams[2], &nTimeout)) { - return InitError(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2])); - } - bool found = false; - for (int j=0; j<(int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) - { - if (vDeploymentParams[0].compare(VersionBitsDeploymentInfo[j].name) == 0) { - UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout); - found = true; - LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld\n", vDeploymentParams[0], nStartTime, nTimeout); - break; - } - } - if (!found) { - return InitError(strprintf("Invalid deployment (%s)", vDeploymentParams[0])); - } - } - } return true; } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 766e34e5b5..f7874e6882 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) InitSignatureCache(); InitScriptExecutionCache(); fCheckBlockIndex = true; + // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests. + // TODO: fix the code to support SegWit blocks. + gArgs.ForceSetArg("-vbparams", strprintf("segwit:0:%d", (int64_t)Consensus::BIP9Deployment::NO_TIMEOUT)); SelectParams(chainName); noui_connect(); } @@ -128,9 +132,6 @@ TestingSetup::~TestingSetup() TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) { - // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests. - // TODO: fix the code to support SegWit blocks. - UpdateVersionBitsParameters(Consensus::DEPLOYMENT_SEGWIT, 0, Consensus::BIP9Deployment::NO_TIMEOUT); // Generate a 100-block chain: coinbaseKey.MakeNewKey(true); CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; From 1d0ce94a54be17b139a052b8e7b4605fe9ac1ecd Mon Sep 17 00:00:00 2001 From: Justin Turner Arthur Date: Sun, 23 Sep 2018 21:30:22 -0500 Subject: [PATCH 048/263] Fix for incorrect version attr set on functional test segwit block. --- test/functional/p2p_segwit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 58bfd1c942..1b3c5bd1fb 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -205,7 +205,7 @@ def build_next_block(self, version=4): height = self.nodes[0].getblockcount() + 1 block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1 block = create_block(int(tip, 16), create_coinbase(height), block_time) - block.version = version + block.nVersion = version block.rehash() return block From 97ddc6026b4e14ee0bb4c5b04a7824ac0a7e23ab Mon Sep 17 00:00:00 2001 From: practicalswift Date: Mon, 24 Sep 2018 15:00:44 +0200 Subject: [PATCH 049/263] validation: Pass chainparams in AcceptToMemoryPoolWorker(...) --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 458458d85d..80ae2428dc 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -918,7 +918,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks (using TestBlockValidity), however allowing such // transactions into the mempool can be exploited as a DoS attack. - unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), Params().GetConsensus()); + unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), chainparams.GetConsensus()); if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, true, txdata)) { return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); From db15805668e923c3493d77122d20926496cf6a1a Mon Sep 17 00:00:00 2001 From: gustavonalle Date: Mon, 24 Sep 2018 16:10:23 +0100 Subject: [PATCH 050/263] [wallet] Ensure wallet is unlocked before signing --- src/wallet/rpcwallet.cpp | 2 ++ test/functional/rpc_signrawtransaction.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1a2dff9a96..8a402546a7 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3116,6 +3116,8 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) // Sign the transaction LOCK2(cs_main, pwallet->cs_wallet); + EnsureWalletIsUnlocked(pwallet); + return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]); } diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 5c07f2ccae..98648dd436 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -45,6 +45,14 @@ def successful_signing_test(self): # 2) No script verification error occurred assert 'errors' not in rawTxSigned + def test_with_lock_outputs(self): + """Test correct error reporting when trying to sign a locked output""" + self.nodes[0].encryptwallet("password") + self.restart_node(0) + rawTx = '020000000156b958f78e3f24e0b2f4e4db1255426b0902027cb37e3ddadb52e37c3557dddb0000000000ffffffff01c0a6b929010000001600149a2ee8c77140a053f36018ac8124a6ececc1668a00000000' + + assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].signrawtransactionwithwallet, rawTx) + def script_verification_error_test(self): """Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script. @@ -138,6 +146,7 @@ def script_verification_error_test(self): def run_test(self): self.successful_signing_test() self.script_verification_error_test() + self.test_with_lock_outputs() if __name__ == '__main__': From edb5350c32cdf7f8487777b5cc1a2ebfcdfc9e75 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Mon, 24 Sep 2018 16:30:53 -0400 Subject: [PATCH 051/263] Move NotifyNumConnectionsChanged logic to private method. --- src/net.cpp | 27 ++++++++++++++++----------- src/net.h | 2 ++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index c51a1b4a74..767275247d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1153,9 +1153,22 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } +void CConnman::NotifyNumConnectionsChanged() +{ + size_t vNodesSize; + { + LOCK(cs_vNodes); + vNodesSize = vNodes.size(); + } + if(vNodesSize != nPrevNodeCount) { + nPrevNodeCount = vNodesSize; + if(clientInterface) + clientInterface->NotifyNumConnectionsChanged(vNodesSize); + } +} + void CConnman::ThreadSocketHandler() { - unsigned int nPrevNodeCount = 0; while (!interruptNet) { // @@ -1219,16 +1232,7 @@ void CConnman::ThreadSocketHandler() } } } - size_t vNodesSize; - { - LOCK(cs_vNodes); - vNodesSize = vNodes.size(); - } - if(vNodesSize != nPrevNodeCount) { - nPrevNodeCount = vNodesSize; - if(clientInterface) - clientInterface->NotifyNumConnectionsChanged(vNodesSize); - } + NotifyNumConnectionsChanged(); // // Find which sockets have data to receive @@ -2217,6 +2221,7 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe setBannedIsDirty = false; fAddressesInitialized = false; nLastNodeId = 0; + nPrevNodeCount = 0; nSendBufferMaxSize = 0; nReceiveFloodSize = 0; flagInterruptMsgProc = false; diff --git a/src/net.h b/src/net.h index 9f6c426ab7..ba5cd4f5c7 100644 --- a/src/net.h +++ b/src/net.h @@ -336,6 +336,7 @@ class CConnman void ThreadOpenConnections(std::vector connect); void ThreadMessageHandler(); void AcceptConnection(const ListenSocket& hListenSocket); + void NotifyNumConnectionsChanged(); void ThreadSocketHandler(); void ThreadDNSAddressSeed(); @@ -406,6 +407,7 @@ class CConnman std::list vNodesDisconnected; mutable CCriticalSection cs_vNodes; std::atomic nLastNodeId; + unsigned int nPrevNodeCount; /** Services this instance offers */ ServiceFlags nLocalServices; From 7479b63d9109ccaf3708a92dc65dc24556576551 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Mon, 24 Sep 2018 16:36:58 -0400 Subject: [PATCH 052/263] Move DisconnectNodes logic to private method. --- src/net.cpp | 122 ++++++++++++++++++++++++++-------------------------- src/net.h | 1 + 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 767275247d..006e094fc7 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1153,85 +1153,87 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } -void CConnman::NotifyNumConnectionsChanged() +void CConnman::DisconnectNodes() { - size_t vNodesSize; { LOCK(cs_vNodes); - vNodesSize = vNodes.size(); - } - if(vNodesSize != nPrevNodeCount) { - nPrevNodeCount = vNodesSize; - if(clientInterface) - clientInterface->NotifyNumConnectionsChanged(vNodesSize); - } -} - -void CConnman::ThreadSocketHandler() -{ - while (!interruptNet) - { - // - // Disconnect nodes - // - { - LOCK(cs_vNodes); - if (!fNetworkActive) { - // Disconnect any connected nodes - for (CNode* pnode : vNodes) { - if (!pnode->fDisconnect) { - LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId()); - pnode->fDisconnect = true; - } + if (!fNetworkActive) { + // Disconnect any connected nodes + for (CNode* pnode : vNodes) { + if (!pnode->fDisconnect) { + LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId()); + pnode->fDisconnect = true; } } + } - // Disconnect unused nodes - std::vector vNodesCopy = vNodes; - for (CNode* pnode : vNodesCopy) + // Disconnect unused nodes + std::vector vNodesCopy = vNodes; + for (CNode* pnode : vNodesCopy) + { + if (pnode->fDisconnect) { - if (pnode->fDisconnect) - { - // remove from vNodes - vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); + // remove from vNodes + vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); - // release outbound grant (if any) - pnode->grantOutbound.Release(); + // release outbound grant (if any) + pnode->grantOutbound.Release(); - // close socket and cleanup - pnode->CloseSocketDisconnect(); + // close socket and cleanup + pnode->CloseSocketDisconnect(); - // hold in disconnected pool until all refs are released - pnode->Release(); - vNodesDisconnected.push_back(pnode); - } + // hold in disconnected pool until all refs are released + pnode->Release(); + vNodesDisconnected.push_back(pnode); } } + } + { + // Delete disconnected nodes + std::list vNodesDisconnectedCopy = vNodesDisconnected; + for (CNode* pnode : vNodesDisconnectedCopy) { - // Delete disconnected nodes - std::list vNodesDisconnectedCopy = vNodesDisconnected; - for (CNode* pnode : vNodesDisconnectedCopy) - { - // wait until threads are done using it - if (pnode->GetRefCount() <= 0) { - bool fDelete = false; - { - TRY_LOCK(pnode->cs_inventory, lockInv); - if (lockInv) { - TRY_LOCK(pnode->cs_vSend, lockSend); - if (lockSend) { - fDelete = true; - } + // wait until threads are done using it + if (pnode->GetRefCount() <= 0) { + bool fDelete = false; + { + TRY_LOCK(pnode->cs_inventory, lockInv); + if (lockInv) { + TRY_LOCK(pnode->cs_vSend, lockSend); + if (lockSend) { + fDelete = true; } } - if (fDelete) { - vNodesDisconnected.remove(pnode); - DeleteNode(pnode); - } + } + if (fDelete) { + vNodesDisconnected.remove(pnode); + DeleteNode(pnode); } } } + } +} + +void CConnman::NotifyNumConnectionsChanged() +{ + size_t vNodesSize; + { + LOCK(cs_vNodes); + vNodesSize = vNodes.size(); + } + if(vNodesSize != nPrevNodeCount) { + nPrevNodeCount = vNodesSize; + if(clientInterface) + clientInterface->NotifyNumConnectionsChanged(vNodesSize); + } +} + +void CConnman::ThreadSocketHandler() +{ + while (!interruptNet) + { + DisconnectNodes(); NotifyNumConnectionsChanged(); // diff --git a/src/net.h b/src/net.h index ba5cd4f5c7..f6af2a3bab 100644 --- a/src/net.h +++ b/src/net.h @@ -336,6 +336,7 @@ class CConnman void ThreadOpenConnections(std::vector connect); void ThreadMessageHandler(); void AcceptConnection(const ListenSocket& hListenSocket); + void DisconnectNodes(); void NotifyNumConnectionsChanged(); void ThreadSocketHandler(); void ThreadDNSAddressSeed(); From 67654b64056e8b7e8312607d7275f73dbc9548ad Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Thu, 20 Sep 2018 15:33:07 +0800 Subject: [PATCH 053/263] tests: write the notification to different files to avoid race condition --- appveyor.yml | 2 +- test/functional/feature_notifications.py | 54 ++++++++++++------------ 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c2e1c00b8d..84cd596bbd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -55,5 +55,5 @@ test_script: - ps: src\bench_bitcoin.exe -evals=1 -scaling=0 - ps: python test\util\bitcoin-util-test.py - cmd: python test\util\rpcauth-test.py -- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude "feature_notifications,wallet_multiwallet,wallet_multiwallet.py --usecli" +- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude "wallet_multiwallet,wallet_multiwallet.py --usecli" deploy: off diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index 25a7329a0d..a93443f2db 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -17,17 +17,20 @@ def skip_test_if_missing_module(self): self.skip_if_no_wallet() def setup_network(self): - self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") - self.block_filename = os.path.join(self.options.tmpdir, "blocks.txt") - self.tx_filename = os.path.join(self.options.tmpdir, "transactions.txt") + self.alertnotify_dir = os.path.join(self.options.tmpdir, "alertnotify") + self.blocknotify_dir = os.path.join(self.options.tmpdir, "blocknotify") + self.walletnotify_dir = os.path.join(self.options.tmpdir, "walletnotify") + os.mkdir(self.alertnotify_dir) + os.mkdir(self.blocknotify_dir) + os.mkdir(self.walletnotify_dir) # -alertnotify and -blocknotify on node0, walletnotify on node1 self.extra_args = [["-blockversion=2", - "-alertnotify=echo %%s >> %s" % self.alert_filename, - "-blocknotify=echo %%s >> %s" % self.block_filename], + "-alertnotify=echo > {}".format(os.path.join(self.alertnotify_dir, '%s')), + "-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s'))], ["-blockversion=211", "-rescan", - "-walletnotify=echo %%s >> %s" % self.tx_filename]] + "-walletnotify=echo > {}".format(os.path.join(self.walletnotify_dir, '%s'))]] super().setup_network() def run_test(self): @@ -35,34 +38,32 @@ def run_test(self): block_count = 10 blocks = self.nodes[1].generate(block_count) - # wait at most 10 seconds for expected file size before reading the content - wait_until(lambda: os.path.isfile(self.block_filename) and os.stat(self.block_filename).st_size >= (block_count * 65), timeout=10) + # wait at most 10 seconds for expected number of files before reading the content + wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10) - # file content should equal the generated blocks hashes - with open(self.block_filename, 'r', encoding="utf-8") as f: - assert_equal(sorted(blocks), sorted(l.strip() for l in f.read().splitlines())) + # directory content should equal the generated blocks hashes + assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir))) self.log.info("test -walletnotify") - # wait at most 10 seconds for expected file size before reading the content - wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat(self.tx_filename).st_size >= (block_count * 65), timeout=10) + # wait at most 10 seconds for expected number of files before reading the content + wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) - # file content should equal the generated transaction hashes + # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) - with open(self.tx_filename, 'r', encoding="ascii") as f: - assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines())) - os.remove(self.tx_filename) + assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) + for tx_file in os.listdir(self.walletnotify_dir): + os.remove(os.path.join(self.walletnotify_dir, tx_file)) self.log.info("test -walletnotify after rescan") # restart node to rescan to force wallet notifications self.restart_node(1) connect_nodes_bi(self.nodes, 0, 1) - wait_until(lambda: os.path.isfile(self.tx_filename) and os.stat(self.tx_filename).st_size >= (block_count * 65), timeout=10) + wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) - # file content should equal the generated transaction hashes + # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) - with open(self.tx_filename, 'r', encoding="ascii") as f: - assert_equal(sorted(txids_rpc), sorted(l.strip() for l in f.read().splitlines())) + assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) # Mine another 41 up-version blocks. -alertnotify should trigger on the 51st. self.log.info("test -alertnotify") @@ -70,20 +71,17 @@ def run_test(self): self.sync_all() # Give bitcoind 10 seconds to write the alert notification - wait_until(lambda: os.path.isfile(self.alert_filename) and os.path.getsize(self.alert_filename), timeout=10) + wait_until(lambda: len(os.listdir(self.alertnotify_dir)), timeout=10) - with open(self.alert_filename, 'r', encoding='utf8') as f: - alert_text = f.read() + for notify_file in os.listdir(self.alertnotify_dir): + os.remove(os.path.join(self.alertnotify_dir, notify_file)) # Mine more up-version blocks, should not get more alerts: self.nodes[1].generate(2) self.sync_all() - with open(self.alert_filename, 'r', encoding='utf8') as f: - alert_text2 = f.read() - self.log.info("-alertnotify should not continue notifying for more unknown version blocks") - assert_equal(alert_text, alert_text2) + assert_equal(len(os.listdir(self.alertnotify_dir)), 0) if __name__ == '__main__': NotificationsTest().main() From 2af9cff11ad3ef27893b4b2009ddbfcb208554a9 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Mon, 24 Sep 2018 16:43:00 -0400 Subject: [PATCH 054/263] Move InactivityCheck logic to private method. --- src/net.cpp | 66 +++++++++++++++++++++++++++-------------------------- src/net.h | 1 + 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 006e094fc7..644fed5ef8 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1229,6 +1229,39 @@ void CConnman::NotifyNumConnectionsChanged() } } +void CConnman::InactivityCheck(CNode *pnode) +{ + int64_t nTime = GetSystemTimeInSeconds(); + if (nTime - pnode->nTimeConnected > 60) + { + if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) + { + LogPrint(BCLog::NET, "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId()); + pnode->fDisconnect = true; + } + else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL) + { + LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend); + pnode->fDisconnect = true; + } + else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60)) + { + LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv); + pnode->fDisconnect = true; + } + else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros()) + { + LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart)); + pnode->fDisconnect = true; + } + else if (!pnode->fSuccessfullyConnected) + { + LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId()); + pnode->fDisconnect = true; + } + } +} + void CConnman::ThreadSocketHandler() { while (!interruptNet) @@ -1425,38 +1458,7 @@ void CConnman::ThreadSocketHandler() } } - // - // Inactivity checking - // - int64_t nTime = GetSystemTimeInSeconds(); - if (nTime - pnode->nTimeConnected > 60) - { - if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) - { - LogPrint(BCLog::NET, "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId()); - pnode->fDisconnect = true; - } - else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL) - { - LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend); - pnode->fDisconnect = true; - } - else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60)) - { - LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv); - pnode->fDisconnect = true; - } - else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros()) - { - LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart)); - pnode->fDisconnect = true; - } - else if (!pnode->fSuccessfullyConnected) - { - LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId()); - pnode->fDisconnect = true; - } - } + InactivityCheck(pnode); } { LOCK(cs_vNodes); diff --git a/src/net.h b/src/net.h index f6af2a3bab..480e9b83f7 100644 --- a/src/net.h +++ b/src/net.h @@ -338,6 +338,7 @@ class CConnman void AcceptConnection(const ListenSocket& hListenSocket); void DisconnectNodes(); void NotifyNumConnectionsChanged(); + void InactivityCheck(CNode *pnode); void ThreadSocketHandler(); void ThreadDNSAddressSeed(); From 032488e6e7b4c2d37f3f434d575d25806ddcb0b0 Mon Sep 17 00:00:00 2001 From: Patrick Strateman Date: Mon, 24 Sep 2018 17:03:17 -0400 Subject: [PATCH 055/263] Move SocketHandler logic to private method. --- src/net.cpp | 328 ++++++++++++++++++++++++++-------------------------- src/net.h | 1 + 2 files changed, 167 insertions(+), 162 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 644fed5ef8..1b47f288fd 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1262,209 +1262,213 @@ void CConnman::InactivityCheck(CNode *pnode) } } -void CConnman::ThreadSocketHandler() +void CConnman::SocketHandler() { - while (!interruptNet) - { - DisconnectNodes(); - NotifyNumConnectionsChanged(); + // + // Find which sockets have data to receive + // + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // frequency to poll pnode->vSend - // - // Find which sockets have data to receive - // - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 50000; // frequency to poll pnode->vSend - - fd_set fdsetRecv; - fd_set fdsetSend; - fd_set fdsetError; - FD_ZERO(&fdsetRecv); - FD_ZERO(&fdsetSend); - FD_ZERO(&fdsetError); - SOCKET hSocketMax = 0; - bool have_fds = false; + fd_set fdsetRecv; + fd_set fdsetSend; + fd_set fdsetError; + FD_ZERO(&fdsetRecv); + FD_ZERO(&fdsetSend); + FD_ZERO(&fdsetError); + SOCKET hSocketMax = 0; + bool have_fds = false; - for (const ListenSocket& hListenSocket : vhListenSocket) { - FD_SET(hListenSocket.socket, &fdsetRecv); - hSocketMax = std::max(hSocketMax, hListenSocket.socket); - have_fds = true; - } + for (const ListenSocket& hListenSocket : vhListenSocket) { + FD_SET(hListenSocket.socket, &fdsetRecv); + hSocketMax = std::max(hSocketMax, hListenSocket.socket); + have_fds = true; + } + { + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) { - LOCK(cs_vNodes); - for (CNode* pnode : vNodes) + // Implement the following logic: + // * If there is data to send, select() for sending data. As this only + // happens when optimistic write failed, we choose to first drain the + // write buffer in this case before receiving more. This avoids + // needlessly queueing received data, if the remote peer is not themselves + // receiving data. This means properly utilizing TCP flow control signalling. + // * Otherwise, if there is space left in the receive buffer, select() for + // receiving data. + // * Hand off all complete messages to the processor, to be handled without + // blocking here. + + bool select_recv = !pnode->fPauseRecv; + bool select_send; { - // Implement the following logic: - // * If there is data to send, select() for sending data. As this only - // happens when optimistic write failed, we choose to first drain the - // write buffer in this case before receiving more. This avoids - // needlessly queueing received data, if the remote peer is not themselves - // receiving data. This means properly utilizing TCP flow control signalling. - // * Otherwise, if there is space left in the receive buffer, select() for - // receiving data. - // * Hand off all complete messages to the processor, to be handled without - // blocking here. - - bool select_recv = !pnode->fPauseRecv; - bool select_send; - { - LOCK(pnode->cs_vSend); - select_send = !pnode->vSendMsg.empty(); - } + LOCK(pnode->cs_vSend); + select_send = !pnode->vSendMsg.empty(); + } - LOCK(pnode->cs_hSocket); - if (pnode->hSocket == INVALID_SOCKET) - continue; + LOCK(pnode->cs_hSocket); + if (pnode->hSocket == INVALID_SOCKET) + continue; - FD_SET(pnode->hSocket, &fdsetError); - hSocketMax = std::max(hSocketMax, pnode->hSocket); - have_fds = true; + FD_SET(pnode->hSocket, &fdsetError); + hSocketMax = std::max(hSocketMax, pnode->hSocket); + have_fds = true; - if (select_send) { - FD_SET(pnode->hSocket, &fdsetSend); - continue; - } - if (select_recv) { - FD_SET(pnode->hSocket, &fdsetRecv); - } + if (select_send) { + FD_SET(pnode->hSocket, &fdsetSend); + continue; + } + if (select_recv) { + FD_SET(pnode->hSocket, &fdsetRecv); } } + } - int nSelect = select(have_fds ? hSocketMax + 1 : 0, - &fdsetRecv, &fdsetSend, &fdsetError, &timeout); - if (interruptNet) - return; + int nSelect = select(have_fds ? hSocketMax + 1 : 0, + &fdsetRecv, &fdsetSend, &fdsetError, &timeout); + if (interruptNet) + return; - if (nSelect == SOCKET_ERROR) + if (nSelect == SOCKET_ERROR) + { + if (have_fds) { - if (have_fds) - { - int nErr = WSAGetLastError(); - LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); - for (unsigned int i = 0; i <= hSocketMax; i++) - FD_SET(i, &fdsetRecv); - } - FD_ZERO(&fdsetSend); - FD_ZERO(&fdsetError); - if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000))) - return; + int nErr = WSAGetLastError(); + LogPrintf("socket select error %s\n", NetworkErrorString(nErr)); + for (unsigned int i = 0; i <= hSocketMax; i++) + FD_SET(i, &fdsetRecv); } + FD_ZERO(&fdsetSend); + FD_ZERO(&fdsetError); + if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000))) + return; + } - // - // Accept new connections - // - for (const ListenSocket& hListenSocket : vhListenSocket) + // + // Accept new connections + // + for (const ListenSocket& hListenSocket : vhListenSocket) + { + if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) { - if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) - { - AcceptConnection(hListenSocket); - } + AcceptConnection(hListenSocket); } + } + + // + // Service each socket + // + std::vector vNodesCopy; + { + LOCK(cs_vNodes); + vNodesCopy = vNodes; + for (CNode* pnode : vNodesCopy) + pnode->AddRef(); + } + for (CNode* pnode : vNodesCopy) + { + if (interruptNet) + return; // - // Service each socket + // Receive // - std::vector vNodesCopy; + bool recvSet = false; + bool sendSet = false; + bool errorSet = false; { - LOCK(cs_vNodes); - vNodesCopy = vNodes; - for (CNode* pnode : vNodesCopy) - pnode->AddRef(); + LOCK(pnode->cs_hSocket); + if (pnode->hSocket == INVALID_SOCKET) + continue; + recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv); + sendSet = FD_ISSET(pnode->hSocket, &fdsetSend); + errorSet = FD_ISSET(pnode->hSocket, &fdsetError); } - for (CNode* pnode : vNodesCopy) + if (recvSet || errorSet) { - if (interruptNet) - return; - - // - // Receive - // - bool recvSet = false; - bool sendSet = false; - bool errorSet = false; + // typical socket buffer is 8K-64K + char pchBuf[0x10000]; + int nBytes = 0; { LOCK(pnode->cs_hSocket); if (pnode->hSocket == INVALID_SOCKET) continue; - recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv); - sendSet = FD_ISSET(pnode->hSocket, &fdsetSend); - errorSet = FD_ISSET(pnode->hSocket, &fdsetError); + nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); } - if (recvSet || errorSet) + if (nBytes > 0) { - // typical socket buffer is 8K-64K - char pchBuf[0x10000]; - int nBytes = 0; - { - LOCK(pnode->cs_hSocket); - if (pnode->hSocket == INVALID_SOCKET) - continue; - nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); - } - if (nBytes > 0) - { - bool notify = false; - if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) - pnode->CloseSocketDisconnect(); - RecordBytesRecv(nBytes); - if (notify) { - size_t nSizeAdded = 0; - auto it(pnode->vRecvMsg.begin()); - for (; it != pnode->vRecvMsg.end(); ++it) { - if (!it->complete()) - break; - nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE; - } - { - LOCK(pnode->cs_vProcessMsg); - pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it); - pnode->nProcessQueueSize += nSizeAdded; - pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize; - } - WakeMessageHandler(); - } - } - else if (nBytes == 0) - { - // socket closed gracefully - if (!pnode->fDisconnect) { - LogPrint(BCLog::NET, "socket closed\n"); - } + bool notify = false; + if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) pnode->CloseSocketDisconnect(); - } - else if (nBytes < 0) - { - // error - int nErr = WSAGetLastError(); - if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + RecordBytesRecv(nBytes); + if (notify) { + size_t nSizeAdded = 0; + auto it(pnode->vRecvMsg.begin()); + for (; it != pnode->vRecvMsg.end(); ++it) { + if (!it->complete()) + break; + nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE; + } { - if (!pnode->fDisconnect) - LogPrintf("socket recv error %s\n", NetworkErrorString(nErr)); - pnode->CloseSocketDisconnect(); + LOCK(pnode->cs_vProcessMsg); + pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it); + pnode->nProcessQueueSize += nSizeAdded; + pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize; } + WakeMessageHandler(); } } - - // - // Send - // - if (sendSet) + else if (nBytes == 0) { - LOCK(pnode->cs_vSend); - size_t nBytes = SocketSendData(pnode); - if (nBytes) { - RecordBytesSent(nBytes); + // socket closed gracefully + if (!pnode->fDisconnect) { + LogPrint(BCLog::NET, "socket closed\n"); + } + pnode->CloseSocketDisconnect(); + } + else if (nBytes < 0) + { + // error + int nErr = WSAGetLastError(); + if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) + { + if (!pnode->fDisconnect) + LogPrintf("socket recv error %s\n", NetworkErrorString(nErr)); + pnode->CloseSocketDisconnect(); } } - - InactivityCheck(pnode); } + + // + // Send + // + if (sendSet) { - LOCK(cs_vNodes); - for (CNode* pnode : vNodesCopy) - pnode->Release(); + LOCK(pnode->cs_vSend); + size_t nBytes = SocketSendData(pnode); + if (nBytes) { + RecordBytesSent(nBytes); + } } + + InactivityCheck(pnode); + } + { + LOCK(cs_vNodes); + for (CNode* pnode : vNodesCopy) + pnode->Release(); + } +} + +void CConnman::ThreadSocketHandler() +{ + while (!interruptNet) + { + DisconnectNodes(); + NotifyNumConnectionsChanged(); + SocketHandler(); } } diff --git a/src/net.h b/src/net.h index 480e9b83f7..03be59131b 100644 --- a/src/net.h +++ b/src/net.h @@ -339,6 +339,7 @@ class CConnman void DisconnectNodes(); void NotifyNumConnectionsChanged(); void InactivityCheck(CNode *pnode); + void SocketHandler(); void ThreadSocketHandler(); void ThreadDNSAddressSeed(); From 854c85ae904075503215f94d6329d38d2d8dfb6b Mon Sep 17 00:00:00 2001 From: James O'Beirne Date: Thu, 12 Jul 2018 14:11:23 -0400 Subject: [PATCH 056/263] test: allow arguments to be forwarded to flake8 in lint-python.sh --- test/lint/lint-python.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh index 4f4542ff0c..d44a585294 100755 --- a/test/lint/lint-python.sh +++ b/test/lint/lint-python.sh @@ -87,4 +87,4 @@ elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then exit 0 fi -PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=E101,E112,E113,E115,E116,E125,E129,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,E901,E902,F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W191,W291,W292,W293,W504,W601,W602,W603,W604,W605,W606 . +PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=E101,E112,E113,E115,E116,E125,E129,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,E901,E902,F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W191,W291,W292,W293,W504,W601,W602,W603,W604,W605,W606 "${@:-.}" From ff40357da10afd16b9efb06c4e6e8981fac8c239 Mon Sep 17 00:00:00 2001 From: Mitchell Cash Date: Mon, 24 Sep 2018 14:50:02 +1000 Subject: [PATCH 057/263] AppVeyor: Move AppVeyor YAML to dot-file-style YAML AppVeyor supports dot-file-style YAML named .appveyor.yml as is. This helps keep the root of the repository clean(ish) and readable by having the CI files as dot-files. --- appveyor.yml => .appveyor.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yml => .appveyor.yml (100%) diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml From 20442f617f7f86cbdde1c41c1165e2b750f756c7 Mon Sep 17 00:00:00 2001 From: gustavonalle Date: Mon, 24 Sep 2018 20:30:16 +0100 Subject: [PATCH 058/263] [wallet] remove redundand restart node --- test/functional/rpc_signrawtransaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 98648dd436..291538df64 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -48,7 +48,7 @@ def successful_signing_test(self): def test_with_lock_outputs(self): """Test correct error reporting when trying to sign a locked output""" self.nodes[0].encryptwallet("password") - self.restart_node(0) + rawTx = '020000000156b958f78e3f24e0b2f4e4db1255426b0902027cb37e3ddadb52e37c3557dddb0000000000ffffffff01c0a6b929010000001600149a2ee8c77140a053f36018ac8124a6ececc1668a00000000' assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].signrawtransactionwithwallet, rawTx) From 9c5af58d51cea7d0cf2a598a9979eeba103b23ff Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Mon, 24 Sep 2018 10:59:17 -0400 Subject: [PATCH 059/263] Consolidate redundant implementations of ParseHashStr This change: * adds a length check to ParseHashStr, appropriate given its use to populate a 256-bit number from a hex str. * allows the caller to handle the failure, which allows for the more appropriate JSONRPCError on failure in prioritisetransaction rpc --- src/bitcoin-tx.cpp | 11 +++-- src/core_io.h | 11 ++++- src/core_read.cpp | 9 ++-- src/rest.cpp | 9 ---- src/test/blockfilter_tests.cpp | 9 ++-- test/util/data/bitcoin-util-test.json | 60 +++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 9ee3e8eee7..a3fcb87675 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -240,10 +240,10 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu throw std::runtime_error("TX input missing separator"); // extract and validate TXID - std::string strTxid = vStrInputParts[0]; - if ((strTxid.size() != 64) || !IsHex(strTxid)) + uint256 txid; + if (!ParseHashStr(vStrInputParts[0], txid)) { throw std::runtime_error("invalid TX input txid"); - uint256 txid(uint256S(strTxid)); + } static const unsigned int minTxOutSz = 9; static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz); @@ -590,7 +590,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) if (!prevOut.checkObject(types)) throw std::runtime_error("prevtxs internal object typecheck fail"); - uint256 txid = ParseHashStr(prevOut["txid"].get_str(), "txid"); + uint256 txid; + if (!ParseHashStr(prevOut["txid"].get_str(), txid)) { + throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')"); + } const int nOut = prevOut["vout"].get_int(); if (nOut < 0) diff --git a/src/core_io.h b/src/core_io.h index d53a45c0cb..2c3b64d81e 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -25,7 +25,16 @@ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDeco bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true); bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); -uint256 ParseHashStr(const std::string&, const std::string& strName); + +/** + * Parse a hex string into 256 bits + * @param[in] strHex a hex-formatted, 64-character string + * @param[out] result the result of the parasing + * @returns true if successful, false if not + * + * @see ParseHashV for an RPC-oriented version of this + */ +bool ParseHashStr(const std::string& strHex, uint256& result); std::vector ParseHexUV(const UniValue& v, const std::string& strName); bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error); int ParseSighashString(const UniValue& sighash); diff --git a/src/core_read.cpp b/src/core_read.cpp index b02016c014..301f99bc1c 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -193,14 +193,13 @@ bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, return true; } -uint256 ParseHashStr(const std::string& strHex, const std::string& strName) +bool ParseHashStr(const std::string& strHex, uint256& result) { - if (!IsHex(strHex)) // Note: IsHex("") is false - throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); + if ((strHex.size() != 64) || !IsHex(strHex)) + return false; - uint256 result; result.SetHex(strHex); - return result; + return true; } std::vector ParseHexUV(const UniValue& v, const std::string& strName) diff --git a/src/rest.cpp b/src/rest.cpp index 7792844992..1850c0b7a6 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -105,15 +105,6 @@ static std::string AvailableDataFormatsString() return formats; } -static bool ParseHashStr(const std::string& strReq, uint256& v) -{ - if (!IsHex(strReq) || (strReq.size() != 64)) - return false; - - v.SetHex(strReq); - return true; -} - static bool CheckWarmup(HTTPRequest* req) { std::string statusmessage; diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index 773de343ea..4941ebd483 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -114,7 +114,8 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) unsigned int pos = 0; /*int block_height =*/ test[pos++].get_int(); - /*uint256 block_hash =*/ ParseHashStr(test[pos++].get_str(), "block_hash"); + uint256 block_hash; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), block_hash)); CBlock block; BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str())); @@ -129,9 +130,11 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) tx_undo.vprevout.emplace_back(txout, 0, false); } - uint256 prev_filter_header_basic = ParseHashStr(test[pos++].get_str(), "prev_filter_header_basic"); + uint256 prev_filter_header_basic; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), prev_filter_header_basic)); std::vector filter_basic = ParseHex(test[pos++].get_str()); - uint256 filter_header_basic = ParseHashStr(test[pos++].get_str(), "filter_header_basic"); + uint256 filter_header_basic; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), filter_header_basic)); BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo); BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic); diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index f2213f4f2e..761923a818 100644 --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -102,6 +102,30 @@ "error_txt": "error: Invalid TX locktime requested", "description": "Tests the check for invalid locktime value" }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=Z897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid invalid hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid valid hex but too short" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f12:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid valid hex but too long" + }, { "exec": "./bitcoin-tx", "args": ["-create", @@ -280,6 +304,42 @@ "error_txt": "error: prevtxs internal object typecheck fail", "description": "Tests the check for invalid vout index in prevtxs for sign" }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not 'Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412')", + "description": "Tests the check for invalid txid due to invalid hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594')", + "description": "Tests the check for invalid txid valid hex, but too short" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512')", + "description": "Tests the check for invalid txid valid hex, but too long" + }, { "exec": "./bitcoin-tx", "args": ["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"], From c7b3e487f229142795a0b3ce6ce409ce7084d966 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Tue, 25 Sep 2018 10:51:46 +0800 Subject: [PATCH 060/263] tests: exclude all tests with difference parameters --- .appveyor.yml | 2 +- test/functional/test_runner.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 84cd596bbd..d7ce2224e9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -55,5 +55,5 @@ test_script: - ps: src\bench_bitcoin.exe -evals=1 -scaling=0 - ps: python test\util\bitcoin-util-test.py - cmd: python test\util\rpcauth-test.py -- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude "wallet_multiwallet,wallet_multiwallet.py --usecli" +- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude wallet_multiwallet deploy: off diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 28437f8925..d9960460d9 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -285,11 +285,13 @@ def main(): # Remove the test cases that the user has explicitly asked to exclude. if args.exclude: - exclude_tests = [re.sub("\.py$", "", test) + (".py" if ".py" not in test else "") for test in args.exclude.split(',')] + exclude_tests = [test.split('.py')[0] for test in args.exclude.split(',')] for exclude_test in exclude_tests: - if exclude_test in test_list: - test_list.remove(exclude_test) - else: + # Remove .py and .py --arg from the test list + exclude_list = [test for test in test_list if test.split('.py')[0] == exclude_test] + for exclude_item in exclude_list: + test_list.remove(exclude_item) + if not exclude_list: print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], exclude_test)) if not test_list: From faa4043c660c9a61d304ba1375ce7a32e576ae79 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 23 Sep 2018 11:34:51 -0400 Subject: [PATCH 061/263] qa: Run more tests with wallet disabled --- .travis.yml | 2 +- test/functional/feature_config_args.py | 10 +++-- test/functional/feature_notifications.py | 46 +++++++++++------------ test/functional/interface_bitcoin_cli.py | 32 ++++++++-------- test/functional/interface_zmq.py | 24 ++++++------ test/functional/test_framework/address.py | 3 ++ 6 files changed, 63 insertions(+), 54 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8819d38914..647d117733 100644 --- a/.travis.yml +++ b/.travis.yml @@ -121,7 +121,7 @@ jobs: - stage: test env: >- HOST=x86_64-unknown-linux-gnu - PACKAGES="python3" + PACKAGES="python3-zmq" DEP_OPTS="NO_WALLET=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 1124119e2b..492772d5e3 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -14,9 +14,6 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def test_config_file_parser(self): # Assume node is stopped @@ -68,13 +65,18 @@ def run_test(self): # Temporarily disabled, because this test would access the user's home dir (~/.bitcoin) #self.start_node(0, ['-conf='+conf_file, '-wallet=w1']) #self.stop_node(0) + #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'blocks')) + #if self.is_wallet_compiled(): #assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'wallets', 'w1')) # Ensure command line argument overrides datadir in conf os.mkdir(new_data_dir_2) self.nodes[0].datadir = new_data_dir_2 self.start_node(0, ['-datadir='+new_data_dir_2, '-conf='+conf_file, '-wallet=w2']) - assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'wallets', 'w2')) + assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'blocks')) + if self.is_wallet_compiled(): + assert os.path.exists(os.path.join(new_data_dir_2, 'regtest', 'wallets', 'w2')) + if __name__ == '__main__': ConfArgsTest().main() diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index a93443f2db..90dc4c8e2b 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -5,17 +5,16 @@ """Test the -alertnotify, -blocknotify and -walletnotify options.""" import os +from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, wait_until, connect_nodes_bi + class NotificationsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def setup_network(self): self.alertnotify_dir = os.path.join(self.options.tmpdir, "alertnotify") self.blocknotify_dir = os.path.join(self.options.tmpdir, "blocknotify") @@ -25,7 +24,7 @@ def setup_network(self): os.mkdir(self.walletnotify_dir) # -alertnotify and -blocknotify on node0, walletnotify on node1 - self.extra_args = [["-blockversion=2", + self.extra_args = [[ "-alertnotify=echo > {}".format(os.path.join(self.alertnotify_dir, '%s')), "-blocknotify=echo > {}".format(os.path.join(self.blocknotify_dir, '%s'))], ["-blockversion=211", @@ -36,7 +35,7 @@ def setup_network(self): def run_test(self): self.log.info("test -blocknotify") block_count = 10 - blocks = self.nodes[1].generate(block_count) + blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE) # wait at most 10 seconds for expected number of files before reading the content wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10) @@ -44,30 +43,31 @@ def run_test(self): # directory content should equal the generated blocks hashes assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir))) - self.log.info("test -walletnotify") - # wait at most 10 seconds for expected number of files before reading the content - wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) + if self.is_wallet_compiled(): + self.log.info("test -walletnotify") + # wait at most 10 seconds for expected number of files before reading the content + wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) - # directory content should equal the generated transaction hashes - txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) - assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) - for tx_file in os.listdir(self.walletnotify_dir): - os.remove(os.path.join(self.walletnotify_dir, tx_file)) + # directory content should equal the generated transaction hashes + txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) + assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) + for tx_file in os.listdir(self.walletnotify_dir): + os.remove(os.path.join(self.walletnotify_dir, tx_file)) - self.log.info("test -walletnotify after rescan") - # restart node to rescan to force wallet notifications - self.restart_node(1) - connect_nodes_bi(self.nodes, 0, 1) + self.log.info("test -walletnotify after rescan") + # restart node to rescan to force wallet notifications + self.restart_node(1) + connect_nodes_bi(self.nodes, 0, 1) - wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) + wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) - # directory content should equal the generated transaction hashes - txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) - assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) + # directory content should equal the generated transaction hashes + txids_rpc = list(map(lambda t: t['txid'], self.nodes[1].listtransactions("*", block_count))) + assert_equal(sorted(txids_rpc), sorted(os.listdir(self.walletnotify_dir))) # Mine another 41 up-version blocks. -alertnotify should trigger on the 51st. self.log.info("test -alertnotify") - self.nodes[1].generate(41) + self.nodes[1].generatetoaddress(41, ADDRESS_BCRT1_UNSPENDABLE) self.sync_all() # Give bitcoind 10 seconds to write the alert notification @@ -77,7 +77,7 @@ def run_test(self): os.remove(os.path.join(self.alertnotify_dir, notify_file)) # Mine more up-version blocks, should not get more alerts: - self.nodes[1].generate(2) + self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE) self.sync_all() self.log.info("-alertnotify should not continue notifying for more unknown version blocks") diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index f311858bee..58cdaf861f 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -12,9 +12,6 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - def run_test(self): """Main test logic""" @@ -22,9 +19,10 @@ def run_test(self): assert("Bitcoin Core RPC client version" in cli_response) self.log.info("Compare responses from gewalletinfo RPC and `bitcoin-cli getwalletinfo`") - cli_response = self.nodes[0].cli.getwalletinfo() - rpc_response = self.nodes[0].getwalletinfo() - assert_equal(cli_response, rpc_response) + if self.is_wallet_compiled(): + cli_response = self.nodes[0].cli.getwalletinfo() + rpc_response = self.nodes[0].getwalletinfo() + assert_equal(cli_response, rpc_response) self.log.info("Compare responses from getblockchaininfo RPC and `bitcoin-cli getblockchaininfo`") cli_response = self.nodes[0].cli.getblockchaininfo() @@ -52,26 +50,30 @@ def run_test(self): self.log.info("Compare responses from `bitcoin-cli -getinfo` and the RPCs data is retrieved from.") cli_get_info = self.nodes[0].cli('-getinfo').send_cli() - wallet_info = self.nodes[0].getwalletinfo() + if self.is_wallet_compiled(): + wallet_info = self.nodes[0].getwalletinfo() network_info = self.nodes[0].getnetworkinfo() blockchain_info = self.nodes[0].getblockchaininfo() assert_equal(cli_get_info['version'], network_info['version']) assert_equal(cli_get_info['protocolversion'], network_info['protocolversion']) - assert_equal(cli_get_info['walletversion'], wallet_info['walletversion']) - assert_equal(cli_get_info['balance'], wallet_info['balance']) + if self.is_wallet_compiled(): + assert_equal(cli_get_info['walletversion'], wallet_info['walletversion']) + assert_equal(cli_get_info['balance'], wallet_info['balance']) assert_equal(cli_get_info['blocks'], blockchain_info['blocks']) assert_equal(cli_get_info['timeoffset'], network_info['timeoffset']) assert_equal(cli_get_info['connections'], network_info['connections']) assert_equal(cli_get_info['proxy'], network_info['networks'][0]['proxy']) assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty']) assert_equal(cli_get_info['testnet'], blockchain_info['chain'] == "test") - assert_equal(cli_get_info['balance'], wallet_info['balance']) - assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest']) - assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize']) - assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee']) - assert_equal(cli_get_info['relayfee'], network_info['relayfee']) - # unlocked_until is not tested because the wallet is not encrypted + if self.is_wallet_compiled(): + assert_equal(cli_get_info['balance'], wallet_info['balance']) + assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest']) + assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize']) + assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee']) + assert_equal(cli_get_info['relayfee'], network_info['relayfee']) + # unlocked_until is not tested because the wallet is not encrypted + if __name__ == '__main__': TestBitcoinCli().main() diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 1c518eab75..d544aaebe7 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -5,6 +5,7 @@ """Test the ZMQ notification interface.""" import struct +from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE from test_framework.test_framework import BitcoinTestFramework from test_framework.messages import CTransaction from test_framework.util import ( @@ -41,7 +42,6 @@ def set_test_params(self): def skip_test_if_missing_module(self): self.skip_if_no_py3_zmq() self.skip_if_no_bitcoind_zmq() - self.skip_if_no_wallet() def setup_nodes(self): import zmq @@ -81,7 +81,7 @@ def run_test(self): def _zmq_test(self): num_blocks = 5 self.log.info("Generate %(n)d blocks (and %(n)d coinbase txes)" % {"n": num_blocks}) - genhashes = self.nodes[0].generate(num_blocks) + genhashes = self.nodes[0].generatetoaddress(num_blocks, ADDRESS_BCRT1_UNSPENDABLE) self.sync_all() for x in range(num_blocks): @@ -105,17 +105,19 @@ def _zmq_test(self): block = self.rawblock.receive() assert_equal(genhashes[x], bytes_to_hex_str(hash256(block[:80]))) - self.log.info("Wait for tx from second node") - payment_txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) - self.sync_all() + if self.is_wallet_compiled(): + self.log.info("Wait for tx from second node") + payment_txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) + self.sync_all() + + # Should receive the broadcasted txid. + txid = self.hashtx.receive() + assert_equal(payment_txid, bytes_to_hex_str(txid)) - # Should receive the broadcasted txid. - txid = self.hashtx.receive() - assert_equal(payment_txid, bytes_to_hex_str(txid)) + # Should receive the broadcasted raw transaction. + hex = self.rawtx.receive() + assert_equal(payment_txid, bytes_to_hex_str(hash256(hex))) - # Should receive the broadcasted raw transaction. - hex = self.rawtx.receive() - assert_equal(payment_txid, bytes_to_hex_str(hash256(hex))) if __name__ == '__main__': ZMQTest().main() diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index d1fb97b024..456d43aa2e 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -9,8 +9,11 @@ from . import segwit_addr +ADDRESS_BCRT1_UNSPENDABLE = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj' + chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + def byte_to_base58(b, version): result = '' str = bytes_to_hex_str(b) From 86eb3b3f1ab594142b6baa9576717ff121f3b745 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sat, 4 Aug 2018 13:27:38 +0000 Subject: [PATCH 062/263] utils: Add fsbridge fstream function wrapper --- src/fs.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fs.h | 51 +++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/src/fs.cpp b/src/fs.cpp index df79b5e3df..a146107c4c 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -113,4 +113,106 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e) #endif } +#ifdef WIN32 +#ifdef __GLIBCXX__ + +// reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270 + +static std::string openmodeToStr(std::ios_base::openmode mode) +{ + switch (mode & ~std::ios_base::ate) { + case std::ios_base::out: + case std::ios_base::out | std::ios_base::trunc: + return "w"; + case std::ios_base::out | std::ios_base::app: + case std::ios_base::app: + return "a"; + case std::ios_base::in: + return "r"; + case std::ios_base::in | std::ios_base::out: + return "r+"; + case std::ios_base::in | std::ios_base::out | std::ios_base::trunc: + return "w+"; + case std::ios_base::in | std::ios_base::out | std::ios_base::app: + case std::ios_base::in | std::ios_base::app: + return "a+"; + case std::ios_base::out | std::ios_base::binary: + case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: + return "wb"; + case std::ios_base::out | std::ios_base::app | std::ios_base::binary: + case std::ios_base::app | std::ios_base::binary: + return "ab"; + case std::ios_base::in | std::ios_base::binary: + return "rb"; + case std::ios_base::in | std::ios_base::out | std::ios_base::binary: + return "r+b"; + case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: + return "w+b"; + case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary: + case std::ios_base::in | std::ios_base::app | std::ios_base::binary: + return "a+b"; + default: + return std::string(); + } +} + +void ifstream::open(const fs::path& p, std::ios_base::openmode mode) +{ + close(); + m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); + if (m_file == nullptr) { + return; + } + m_filebuf = __gnu_cxx::stdio_filebuf(m_file, mode); + rdbuf(&m_filebuf); + if (mode & std::ios_base::ate) { + seekg(0, std::ios_base::end); + } +} + +void ifstream::close() +{ + if (m_file != nullptr) { + m_filebuf.close(); + fclose(m_file); + } + m_file = nullptr; +} + +void ofstream::open(const fs::path& p, std::ios_base::openmode mode) +{ + close(); + m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); + if (m_file == nullptr) { + return; + } + m_filebuf = __gnu_cxx::stdio_filebuf(m_file, mode); + rdbuf(&m_filebuf); + if (mode & std::ios_base::ate) { + seekp(0, std::ios_base::end); + } +} + +void ofstream::close() +{ + if (m_file != nullptr) { + m_filebuf.close(); + fclose(m_file); + } + m_file = nullptr; +} +#else // __GLIBCXX__ + +static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t), + "Warning: This build is using boost::filesystem ofstream and ifstream " + "implementations which will fail to open paths containing multibyte " + "characters. You should delete this static_assert to ignore this warning, " + "or switch to a different C++ standard library like the Microsoft C++ " + "Standard Library (where boost uses non-standard extensions to construct " + "stream objects with wide filenames), or the GNU libstdc++ library (where " + "a more complicated workaround has been implemented above)."); + +#endif // __GLIBCXX__ +#endif // WIN32 + } // fsbridge diff --git a/src/fs.h b/src/fs.h index a7074f446a..bdccb15232 100644 --- a/src/fs.h +++ b/src/fs.h @@ -7,6 +7,9 @@ #include #include +#if defined WIN32 && defined __GLIBCXX__ +#include +#endif #include #include @@ -39,6 +42,54 @@ namespace fsbridge { }; std::string get_filesystem_error_message(const fs::filesystem_error& e); + + // GNU libstdc++ specific workaround for opening UTF-8 paths on Windows. + // + // On Windows, it is only possible to reliably access multibyte file paths through + // `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't + // require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't + // provide them (in contrast to the Microsoft C++ library, see + // https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032), + // Boost is forced to fall back to `char` constructors which may not work properly. + // + // Work around this issue by creating stream objects with `_wfopen` in + // combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed + // with an upgrade to C++17, where streams can be constructed directly from + // `std::filesystem::path` objects. + +#if defined WIN32 && defined __GLIBCXX__ + class ifstream : public std::istream + { + public: + ifstream() = default; + explicit ifstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in) { open(p, mode); } + ~ifstream() { close(); } + void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in); + bool is_open() { return m_filebuf.is_open(); } + void close(); + + private: + __gnu_cxx::stdio_filebuf m_filebuf; + FILE* m_file = nullptr; + }; + class ofstream : public std::ostream + { + public: + ofstream() = default; + explicit ofstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out) { open(p, mode); } + ~ofstream() { close(); } + void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out); + bool is_open() { return m_filebuf.is_open(); } + void close(); + + private: + __gnu_cxx::stdio_filebuf m_filebuf; + FILE* m_file = nullptr; + }; +#else // !(WIN32 && __GLIBCXX__) + typedef fs::ifstream ifstream; + typedef fs::ofstream ofstream; +#endif // WIN32 && __GLIBCXX__ }; #endif // BITCOIN_FS_H From a554cc901a32f41162089d6b20ad39d5aeff0583 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sat, 4 Aug 2018 13:32:13 +0000 Subject: [PATCH 063/263] Move boost/std fstream to fsbridge --- src/qt/guiutil.cpp | 6 +++--- src/rpc/protocol.cpp | 10 ++++------ src/util.cpp | 4 ++-- src/wallet/rpcdump.cpp | 9 ++++----- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index b894fc8166..5f6af61a70 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -367,7 +367,7 @@ bool openBitcoinConf() fs::path pathConfig = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)); /* Create the file */ - fs::ofstream configFile(pathConfig, std::ios_base::app); + fsbridge::ofstream configFile(pathConfig, std::ios_base::app); if (!configFile.good()) return false; @@ -611,7 +611,7 @@ fs::path static GetAutostartFilePath() bool GetStartOnSystemStartup() { - fs::ifstream optionFile(GetAutostartFilePath()); + fsbridge::ifstream optionFile(GetAutostartFilePath()); if (!optionFile.good()) return false; // Scan through file for "Hidden=true": @@ -642,7 +642,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) fs::create_directories(GetAutostartDir()); - fs::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc); + fsbridge::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc); if (!optionFile.good()) return false; std::string chain = gArgs.GetChainName(); diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp index 55bebb5662..ee178f34ce 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -12,8 +12,6 @@ #include #include -#include - /** * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were @@ -85,9 +83,9 @@ bool GenerateAuthCookie(std::string *cookie_out) /** the umask determines what permissions are used to create this file - * these are set to 077 in init.cpp unless overridden with -sysperms. */ - std::ofstream file; + fsbridge::ofstream file; fs::path filepath_tmp = GetAuthCookieFile(true); - file.open(filepath_tmp.string().c_str()); + file.open(filepath_tmp); if (!file.is_open()) { LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string()); return false; @@ -109,10 +107,10 @@ bool GenerateAuthCookie(std::string *cookie_out) bool GetAuthCookie(std::string *cookie_out) { - std::ifstream file; + fsbridge::ifstream file; std::string cookie; fs::path filepath = GetAuthCookieFile(); - file.open(filepath.string().c_str()); + file.open(filepath); if (!file.is_open()) return false; std::getline(file, cookie); diff --git a/src/util.cpp b/src/util.cpp index fa624aee90..a8b67dfee4 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -891,7 +891,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME); - fs::ifstream stream(GetConfigFile(confPath)); + fsbridge::ifstream stream(GetConfigFile(confPath)); // ok to not have a config file if (stream.good()) { @@ -924,7 +924,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } for (const std::string& to_include : includeconf) { - fs::ifstream include_config(GetConfigFile(to_include)); + fsbridge::ifstream include_config(GetConfigFile(to_include)); if (include_config.good()) { if (!ReadConfigStream(include_config, error, ignore_invalid_keys)) { return false; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index c97bc38e6f..92457c4644 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -17,7 +17,6 @@ #include -#include #include #include @@ -540,8 +539,8 @@ UniValue importwallet(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - std::ifstream file; - file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate); + fsbridge::ifstream file; + file.open(request.params[0].get_str(), std::ios::in | std::ios::ate); if (!file.is_open()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); } @@ -717,8 +716,8 @@ UniValue dumpwallet(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first"); } - std::ofstream file; - file.open(filepath.string().c_str()); + fsbridge::ofstream file; + file.open(filepath); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); From f86a571edb9627c126b9ccd7da68bd7d1657b8f8 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Fri, 7 Sep 2018 21:12:24 +0800 Subject: [PATCH 064/263] tests: Add test case for std::ios_base::ate --- src/Makefile.test.include | 1 + src/test/fs_tests.cpp | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/test/fs_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 269a6ff805..a82af8f15c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -51,6 +51,7 @@ BITCOIN_TESTS =\ test/cuckoocache_tests.cpp \ test/denialofservice_tests.cpp \ test/descriptor_tests.cpp \ + test/fs_tests.cpp \ test/getarg_tests.cpp \ test/hash_tests.cpp \ test/key_io_tests.cpp \ diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp new file mode 100644 index 0000000000..93aee10bb7 --- /dev/null +++ b/src/test/fs_tests.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2011-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. +// +#include +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(fsbridge_fstream) +{ + fs::path tmpfolder = SetDataDir("fsbridge_fstream"); + // tmpfile1 should be the same as tmpfile2 + fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃"; + fs::path tmpfile2 = tmpfolder / L"fs_tests_₿_🏃"; + { + fsbridge::ofstream file(tmpfile1); + file << "bitcoin"; + } + { + fsbridge::ifstream file(tmpfile2); + std::string input_buffer; + file >> input_buffer; + BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); + } + { + fsbridge::ifstream file(tmpfile1, std::ios_base::in | std::ios_base::ate); + std::string input_buffer; + file >> input_buffer; + BOOST_CHECK_EQUAL(input_buffer, ""); + } + { + fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::app); + file << "tests"; + } + { + fsbridge::ifstream file(tmpfile1); + std::string input_buffer; + file >> input_buffer; + BOOST_CHECK_EQUAL(input_buffer, "bitcointests"); + } + { + fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::trunc); + file << "bitcoin"; + } + { + fsbridge::ifstream file(tmpfile1); + std::string input_buffer; + file >> input_buffer; + BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); + } +} + +BOOST_AUTO_TEST_SUITE_END() From 43c7fbb1e79a4a2219306bf3da1a2dfdf9213f2c Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sat, 15 Sep 2018 04:36:18 +0800 Subject: [PATCH 065/263] Make MSVC compiler read the source code using utf-8 --- build_msvc/common.vcxproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build_msvc/common.vcxproj b/build_msvc/common.vcxproj index 3a53f3bad3..5c87026efe 100644 --- a/build_msvc/common.vcxproj +++ b/build_msvc/common.vcxproj @@ -12,4 +12,9 @@ Outputs="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h"> + + + /utf-8 %(AdditionalOptions) + + \ No newline at end of file From d813266db1f23f49465aa2aca3c3c80a95cf63d9 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 25 Sep 2018 22:07:33 -0400 Subject: [PATCH 066/263] [gitian] use versioned unsigned tarballs instead of generically named ones Instead of re-naming the tarballs used for the code signing step to the generically named tarball that is used, keep the versioned naming. Only copy them to the correct filename when they are needed at build time. --- contrib/gitian-build.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py index 2e8c99247d..faf8b014aa 100755 --- a/contrib/gitian-build.py +++ b/contrib/gitian-build.py @@ -65,14 +65,14 @@ def build(): print('\nCompiling ' + args.version + ' Windows') subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']) - subprocess.check_call('mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz', shell=True) + subprocess.check_call('mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/', shell=True) subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/'+args.version, shell=True) if args.macos: print('\nCompiling ' + args.version + ' MacOS') subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']) - subprocess.check_call('mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz', shell=True) + subprocess.check_call('mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/', shell=True) subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/'+args.version, shell=True) os.chdir(workdir) @@ -92,6 +92,7 @@ def sign(): if args.windows: print('\nSigning ' + args.version + ' Windows') + subprocess.check_call('cp inputs/bitcoin-' + args.version + '-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz', shell=True) subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']) subprocess.check_call('mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/'+args.version, shell=True) @@ -99,6 +100,7 @@ def sign(): if args.macos: print('\nSigning ' + args.version + ' MacOS') + subprocess.check_call('cp inputs/bitcoin-' + args.version + '-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz', shell=True) subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']) subprocess.check_call('mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/'+args.version+'/bitcoin-'+args.version+'-osx.dmg', shell=True) From b0510d78aedde864756199fe71ca98f8e95dd44f Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 9 Sep 2018 13:54:11 +0300 Subject: [PATCH 067/263] Set C locale for amountWidget Fix #13873 --- src/qt/transactionview.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 6d08a3b0fb..68410c8bd6 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -106,7 +106,11 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa } else { amountWidget->setFixedWidth(100); } - amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this)); + QDoubleValidator *amountValidator = new QDoubleValidator(0, 1e20, 8, this); + QLocale amountLocale(QLocale::C); + amountLocale.setNumberOptions(QLocale::RejectGroupSeparator); + amountValidator->setLocale(amountLocale); + amountWidget->setValidator(amountValidator); hlayout->addWidget(amountWidget); // Delay before filtering transactions in ms From fa69ac761441af3e1195fbb4018b18233a4433d2 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 26 Sep 2018 15:44:44 -0400 Subject: [PATCH 068/263] doxygen: Fix member comments --- src/net_processing.h | 2 +- src/netbase.cpp | 26 +++++++++++++------------- src/policy/fees.h | 6 +++--- src/primitives/transaction.h | 2 +- src/script/ismine.cpp | 14 +++++++------- src/txmempool.h | 14 +++++++------- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/net_processing.h b/src/net_processing.h index 496c3c7b0d..04904399dd 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -68,7 +68,7 @@ class PeerLogicValidation final : public CValidationInterface, public NetEventsI void EvictExtraOutboundPeers(int64_t time_in_seconds); private: - int64_t m_stale_tip_check_time; //! Next time to check for stale tip + int64_t m_stale_tip_check_time; //!< Next time to check for stale tip /** Enable BIP61 (sending reject messages) */ const bool m_enable_bip61; diff --git a/src/netbase.cpp b/src/netbase.cpp index 093fd0bdb7..04d5eb12c8 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -191,10 +191,10 @@ enum SOCKSVersion: uint8_t { /** Values defined for METHOD in RFC1928 */ enum SOCKS5Method: uint8_t { - NOAUTH = 0x00, //! No authentication required - GSSAPI = 0x01, //! GSSAPI - USER_PASS = 0x02, //! Username/password - NO_ACCEPTABLE = 0xff, //! No acceptable methods + NOAUTH = 0x00, //!< No authentication required + GSSAPI = 0x01, //!< GSSAPI + USER_PASS = 0x02, //!< Username/password + NO_ACCEPTABLE = 0xff, //!< No acceptable methods }; /** Values defined for CMD in RFC1928 */ @@ -206,15 +206,15 @@ enum SOCKS5Command: uint8_t { /** Values defined for REP in RFC1928 */ enum SOCKS5Reply: uint8_t { - SUCCEEDED = 0x00, //! Succeeded - GENFAILURE = 0x01, //! General failure - NOTALLOWED = 0x02, //! Connection not allowed by ruleset - NETUNREACHABLE = 0x03, //! Network unreachable - HOSTUNREACHABLE = 0x04, //! Network unreachable - CONNREFUSED = 0x05, //! Connection refused - TTLEXPIRED = 0x06, //! TTL expired - CMDUNSUPPORTED = 0x07, //! Command not supported - ATYPEUNSUPPORTED = 0x08, //! Address type not supported + SUCCEEDED = 0x00, //!< Succeeded + GENFAILURE = 0x01, //!< General failure + NOTALLOWED = 0x02, //!< Connection not allowed by ruleset + NETUNREACHABLE = 0x03, //!< Network unreachable + HOSTUNREACHABLE = 0x04, //!< Network unreachable + CONNREFUSED = 0x05, //!< Connection refused + TTLEXPIRED = 0x06, //!< TTL expired + CMDUNSUPPORTED = 0x07, //!< Command not supported + ATYPEUNSUPPORTED = 0x08, //!< Address type not supported }; /** Values defined for ATYPE in RFC1928 */ diff --git a/src/policy/fees.h b/src/policy/fees.h index 2733c5a7de..90f159b48c 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -50,9 +50,9 @@ std::string StringForFeeReason(FeeReason reason); /* Used to determine type of fee estimation requested */ enum class FeeEstimateMode { - UNSET, //! Use default settings based on other criteria - ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates - CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates + UNSET, //!< Use default settings based on other criteria + ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates + CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates }; bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index fb9db508d2..6d8b530f69 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -64,7 +64,7 @@ class CTxIn COutPoint prevout; CScript scriptSig; uint32_t nSequence; - CScriptWitness scriptWitness; //! Only serialized through CTransaction + CScriptWitness scriptWitness; //!< Only serialized through CTransaction /* Setting nSequence to this value for every input in a transaction * disables nLockTime. */ diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 1433ebf42f..51bd2d6e9f 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -23,9 +23,9 @@ namespace { */ enum class IsMineSigVersion { - TOP = 0, //! scriptPubKey execution - P2SH = 1, //! P2SH redeemScript - WITNESS_V0 = 2 //! P2WSH witness script execution + TOP = 0, //!< scriptPubKey execution + P2SH = 1, //!< P2SH redeemScript + WITNESS_V0 = 2, //!< P2WSH witness script execution }; /** @@ -35,10 +35,10 @@ enum class IsMineSigVersion */ enum class IsMineResult { - NO = 0, //! Not ours - WATCH_ONLY = 1, //! Included in watch-only balance - SPENDABLE = 2, //! Included in all balances - INVALID = 3, //! Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness) + NO = 0, //!< Not ours + WATCH_ONLY = 1, //!< Included in watch-only balance + SPENDABLE = 2, //!< Included in all balances + INVALID = 3, //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness) }; bool PermitsUncompressed(IsMineSigVersion sigversion) diff --git a/src/txmempool.h b/src/txmempool.h index 913501fd66..cda78ea90c 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -343,13 +343,13 @@ struct TxMempoolInfo * this is passed to the notification signal. */ enum class MemPoolRemovalReason { - UNKNOWN = 0, //! Manually removed or unknown reason - EXPIRY, //! Expired from mempool - SIZELIMIT, //! Removed in size limiting - REORG, //! Removed for reorganization - BLOCK, //! Removed for block - CONFLICT, //! Removed for conflict with in-block transaction - REPLACED //! Removed for replacement + UNKNOWN = 0, //!< Manually removed or unknown reason + EXPIRY, //!< Expired from mempool + SIZELIMIT, //!< Removed in size limiting + REORG, //!< Removed for reorganization + BLOCK, //!< Removed for block + CONFLICT, //!< Removed for conflict with in-block transaction + REPLACED, //!< Removed for replacement }; class SaltedTxidHasher From 7ac911afe7aee0d3ac742a20d0091c0b75e4535e Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 26 Sep 2018 17:32:07 -0400 Subject: [PATCH 069/263] [docs] Add release notes for removing `-usehd` --- doc/release-notes-14282.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/release-notes-14282.md diff --git a/doc/release-notes-14282.md b/doc/release-notes-14282.md new file mode 100644 index 0000000000..e6d8e0b70c --- /dev/null +++ b/doc/release-notes-14282.md @@ -0,0 +1,6 @@ +Low-level RPC changes +---------------------- + +`-usehd` was removed in version 0.16. From that version onwards, all new +wallets created are hierarchical deterministic wallets. Version 0.18 makes +specifying `-usehd` invalid config. From 3a4449e9ad945313c6637283757de8d539cf790f Mon Sep 17 00:00:00 2001 From: Justin Turner Arthur Date: Sun, 23 Sep 2018 21:34:42 -0500 Subject: [PATCH 070/263] Strictly enforce instance attrs in critical functional test classes. Additionally, removed redundant parentheses and added PEP-8 compliant spacing around those classes. --- test/functional/test_framework/messages.py | 173 ++++++++++++++++----- test/functional/test_framework/script.py | 9 +- 2 files changed, 138 insertions(+), 44 deletions(-) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 0a3907cba4..8e9372767d 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -13,7 +13,11 @@ msg_block, msg_tx, msg_headers, etc.: data structures that represent network messages -ser_*, deser_*: functions that handle serialization/deserialization.""" +ser_*, deser_*: functions that handle serialization/deserialization. + +Classes use __slots__ to ensure extraneous attributes aren't accidentally added +by tests, compromising their intended effect. +""" from codecs import encode import copy import hashlib @@ -185,7 +189,10 @@ def ToHex(obj): # Objects that map to bitcoind objects, which can be serialized/deserialized -class CAddress(): + +class CAddress: + __slots__ = ("ip", "nServices", "pchReserved", "port", "time") + def __init__(self): self.time = 0 self.nServices = 1 @@ -215,7 +222,10 @@ def __repr__(self): return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices, self.ip, self.port) -class CInv(): + +class CInv: + __slots__ = ("hash", "type") + typemap = { 0: "Error", 1: "TX", @@ -244,7 +254,9 @@ def __repr__(self): % (self.typemap[self.type], self.hash) -class CBlockLocator(): +class CBlockLocator: + __slots__ = ("nVersion", "vHave") + def __init__(self): self.nVersion = MY_VERSION self.vHave = [] @@ -264,7 +276,9 @@ def __repr__(self): % (self.nVersion, repr(self.vHave)) -class COutPoint(): +class COutPoint: + __slots__ = ("hash", "n") + def __init__(self, hash=0, n=0): self.hash = hash self.n = n @@ -283,7 +297,9 @@ def __repr__(self): return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n) -class CTxIn(): +class CTxIn: + __slots__ = ("nSequence", "prevout", "scriptSig") + def __init__(self, outpoint=None, scriptSig=b"", nSequence=0): if outpoint is None: self.prevout = COutPoint() @@ -311,7 +327,9 @@ def __repr__(self): self.nSequence) -class CTxOut(): +class CTxOut: + __slots__ = ("nValue", "scriptPubKey") + def __init__(self, nValue=0, scriptPubKey=b""): self.nValue = nValue self.scriptPubKey = scriptPubKey @@ -332,7 +350,9 @@ def __repr__(self): bytes_to_hex_str(self.scriptPubKey)) -class CScriptWitness(): +class CScriptWitness: + __slots__ = ("stack",) + def __init__(self): # stack is a vector of strings self.stack = [] @@ -347,7 +367,9 @@ def is_null(self): return True -class CTxInWitness(): +class CTxInWitness: + __slots__ = ("scriptWitness",) + def __init__(self): self.scriptWitness = CScriptWitness() @@ -364,7 +386,9 @@ def is_null(self): return self.scriptWitness.is_null() -class CTxWitness(): +class CTxWitness: + __slots__ = ("vtxinwit",) + def __init__(self): self.vtxinwit = [] @@ -392,7 +416,10 @@ def is_null(self): return True -class CTransaction(): +class CTransaction: + __slots__ = ("hash", "nLockTime", "nVersion", "sha256", "vin", "vout", + "wit") + def __init__(self, tx=None): if tx is None: self.nVersion = 1 @@ -496,7 +523,10 @@ def __repr__(self): % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) -class CBlockHeader(): +class CBlockHeader: + __slots__ = ("hash", "hashMerkleRoot", "hashPrevBlock", "nBits", "nNonce", + "nTime", "nVersion", "sha256") + def __init__(self, header=None): if header is None: self.set_null() @@ -565,6 +595,8 @@ def __repr__(self): class CBlock(CBlockHeader): + __slots__ = ("vtx",) + def __init__(self, header=None): super(CBlock, self).__init__(header) self.vtx = [] @@ -636,7 +668,9 @@ def __repr__(self): time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx)) -class PrefilledTransaction(): +class PrefilledTransaction: + __slots__ = ("index", "tx") + def __init__(self, index=0, tx = None): self.index = index self.tx = tx @@ -664,8 +698,12 @@ def serialize_with_witness(self): def __repr__(self): return "PrefilledTransaction(index=%d, tx=%s)" % (self.index, repr(self.tx)) + # This is what we send on the wire, in a cmpctblock message. -class P2PHeaderAndShortIDs(): +class P2PHeaderAndShortIDs: + __slots__ = ("header", "nonce", "prefilled_txn", "prefilled_txn_length", + "shortids", "shortids_length") + def __init__(self): self.header = CBlockHeader() self.nonce = 0 @@ -703,9 +741,11 @@ def serialize(self, with_witness=False): def __repr__(self): return "P2PHeaderAndShortIDs(header=%s, nonce=%d, shortids_length=%d, shortids=%s, prefilled_txn_length=%d, prefilledtxn=%s" % (repr(self.header), self.nonce, self.shortids_length, repr(self.shortids), self.prefilled_txn_length, repr(self.prefilled_txn)) + # P2P version of the above that will use witness serialization (for compact # block version 2) class P2PHeaderAndShortWitnessIDs(P2PHeaderAndShortIDs): + __slots__ = () def serialize(self): return super(P2PHeaderAndShortWitnessIDs, self).serialize(with_witness=True) @@ -715,9 +755,12 @@ def calculate_shortid(k0, k1, tx_hash): expected_shortid &= 0x0000ffffffffffff return expected_shortid + # This version gets rid of the array lengths, and reinterprets the differential # encoding into indices that can be used for lookup. -class HeaderAndShortIDs(): +class HeaderAndShortIDs: + __slots__ = ("header", "nonce", "prefilled_txn", "shortids", "use_witness") + def __init__(self, p2pheaders_and_shortids = None): self.header = CBlockHeader() self.nonce = 0 @@ -778,7 +821,8 @@ def __repr__(self): return "HeaderAndShortIDs(header=%s, nonce=%d, shortids=%s, prefilledtxn=%s" % (repr(self.header), self.nonce, repr(self.shortids), repr(self.prefilled_txn)) -class BlockTransactionsRequest(): +class BlockTransactionsRequest: + __slots__ = ("blockhash", "indexes") def __init__(self, blockhash=0, indexes = None): self.blockhash = blockhash @@ -818,7 +862,8 @@ def __repr__(self): return "BlockTransactionsRequest(hash=%064x indexes=%s)" % (self.blockhash, repr(self.indexes)) -class BlockTransactions(): +class BlockTransactions: + __slots__ = ("blockhash", "transactions") def __init__(self, blockhash=0, transactions = None): self.blockhash = blockhash @@ -840,7 +885,10 @@ def serialize(self, with_witness=True): def __repr__(self): return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions)) -class CPartialMerkleTree(): + +class CPartialMerkleTree: + __slots__ = ("fBad", "nTransactions", "vBits", "vHash") + def __init__(self): self.nTransactions = 0 self.vHash = [] @@ -868,7 +916,10 @@ def serialize(self): def __repr__(self): return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits)) -class CMerkleBlock(): + +class CMerkleBlock: + __slots__ = ("header", "txn") + def __init__(self): self.header = CBlockHeader() self.txn = CPartialMerkleTree() @@ -888,7 +939,9 @@ def __repr__(self): # Objects that correspond to messages on the wire -class msg_version(): +class msg_version: + __slots__ = ("addrFrom", "addrTo", "nNonce", "nRelay", "nServices", + "nStartingHeight", "nTime", "nVersion", "strSubVer") command = b"version" def __init__(self): @@ -945,7 +998,8 @@ def __repr__(self): self.strSubVer, self.nStartingHeight, self.nRelay) -class msg_verack(): +class msg_verack: + __slots__ = () command = b"verack" def __init__(self): @@ -961,7 +1015,8 @@ def __repr__(self): return "msg_verack()" -class msg_addr(): +class msg_addr: + __slots__ = ("addrs",) command = b"addr" def __init__(self): @@ -977,7 +1032,8 @@ def __repr__(self): return "msg_addr(addrs=%s)" % (repr(self.addrs)) -class msg_inv(): +class msg_inv: + __slots__ = ("inv",) command = b"inv" def __init__(self, inv=None): @@ -996,7 +1052,8 @@ def __repr__(self): return "msg_inv(inv=%s)" % (repr(self.inv)) -class msg_getdata(): +class msg_getdata: + __slots__ = ("inv",) command = b"getdata" def __init__(self, inv=None): @@ -1012,7 +1069,8 @@ def __repr__(self): return "msg_getdata(inv=%s)" % (repr(self.inv)) -class msg_getblocks(): +class msg_getblocks: + __slots__ = ("locator", "hashstop") command = b"getblocks" def __init__(self): @@ -1035,7 +1093,8 @@ def __repr__(self): % (repr(self.locator), self.hashstop) -class msg_tx(): +class msg_tx: + __slots__ = ("tx",) command = b"tx" def __init__(self, tx=CTransaction()): @@ -1050,13 +1109,16 @@ def serialize(self): def __repr__(self): return "msg_tx(tx=%s)" % (repr(self.tx)) + class msg_witness_tx(msg_tx): + __slots__ = () def serialize(self): return self.tx.serialize_with_witness() -class msg_block(): +class msg_block: + __slots__ = ("block",) command = b"block" def __init__(self, block=None): @@ -1074,9 +1136,12 @@ def serialize(self): def __repr__(self): return "msg_block(block=%s)" % (repr(self.block)) + # for cases where a user needs tighter control over what is sent over the wire # note that the user must supply the name of the command, and the data -class msg_generic(): +class msg_generic: + __slots__ = ("command", "data") + def __init__(self, command, data=None): self.command = command self.data = data @@ -1087,13 +1152,16 @@ def serialize(self): def __repr__(self): return "msg_generic()" -class msg_witness_block(msg_block): +class msg_witness_block(msg_block): + __slots__ = () def serialize(self): r = self.block.serialize(with_witness=True) return r -class msg_getaddr(): + +class msg_getaddr: + __slots__ = () command = b"getaddr" def __init__(self): @@ -1109,7 +1177,8 @@ def __repr__(self): return "msg_getaddr()" -class msg_ping(): +class msg_ping: + __slots__ = ("nonce",) command = b"ping" def __init__(self, nonce=0): @@ -1127,7 +1196,8 @@ def __repr__(self): return "msg_ping(nonce=%08x)" % self.nonce -class msg_pong(): +class msg_pong: + __slots__ = ("nonce",) command = b"pong" def __init__(self, nonce=0): @@ -1145,7 +1215,8 @@ def __repr__(self): return "msg_pong(nonce=%08x)" % self.nonce -class msg_mempool(): +class msg_mempool: + __slots__ = () command = b"mempool" def __init__(self): @@ -1160,7 +1231,9 @@ def serialize(self): def __repr__(self): return "msg_mempool()" -class msg_sendheaders(): + +class msg_sendheaders: + __slots__ = () command = b"sendheaders" def __init__(self): @@ -1180,7 +1253,8 @@ def __repr__(self): # number of entries # vector of hashes # hash_stop (hash of last desired block header, 0 to get as many as possible) -class msg_getheaders(): +class msg_getheaders: + __slots__ = ("hashstop", "locator",) command = b"getheaders" def __init__(self): @@ -1205,7 +1279,8 @@ def __repr__(self): # headers message has # -class msg_headers(): +class msg_headers: + __slots__ = ("headers",) command = b"headers" def __init__(self, headers=None): @@ -1225,7 +1300,8 @@ def __repr__(self): return "msg_headers(headers=%s)" % repr(self.headers) -class msg_reject(): +class msg_reject: + __slots__ = ("code", "data", "message", "reason") command = b"reject" REJECT_MALFORMED = 1 @@ -1256,7 +1332,9 @@ def __repr__(self): return "msg_reject: %s %d %s [%064x]" \ % (self.message, self.code, self.reason, self.data) -class msg_feefilter(): + +class msg_feefilter: + __slots__ = ("feerate",) command = b"feefilter" def __init__(self, feerate=0): @@ -1273,7 +1351,9 @@ def serialize(self): def __repr__(self): return "msg_feefilter(feerate=%08x)" % self.feerate -class msg_sendcmpct(): + +class msg_sendcmpct: + __slots__ = ("announce", "version") command = b"sendcmpct" def __init__(self): @@ -1293,7 +1373,9 @@ def serialize(self): def __repr__(self): return "msg_sendcmpct(announce=%s, version=%lu)" % (self.announce, self.version) -class msg_cmpctblock(): + +class msg_cmpctblock: + __slots__ = ("header_and_shortids",) command = b"cmpctblock" def __init__(self, header_and_shortids = None): @@ -1311,7 +1393,9 @@ def serialize(self): def __repr__(self): return "msg_cmpctblock(HeaderAndShortIDs=%s)" % repr(self.header_and_shortids) -class msg_getblocktxn(): + +class msg_getblocktxn: + __slots__ = ("block_txn_request",) command = b"getblocktxn" def __init__(self): @@ -1329,7 +1413,9 @@ def serialize(self): def __repr__(self): return "msg_getblocktxn(block_txn_request=%s)" % (repr(self.block_txn_request)) -class msg_blocktxn(): + +class msg_blocktxn: + __slots__ = ("block_transactions",) command = b"blocktxn" def __init__(self): @@ -1346,7 +1432,10 @@ def serialize(self): def __repr__(self): return "msg_blocktxn(block_transactions=%s)" % (repr(self.block_transactions)) + class msg_witness_blocktxn(msg_blocktxn): + __slots__ = () + def serialize(self): r = b"" r += self.block_transactions.serialize(with_witness=True) diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 375d6334f7..2fe44010ba 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -26,7 +26,7 @@ def hash160(s): _opcode_instances = [] class CScriptOp(int): """A single script opcode""" - __slots__ = [] + __slots__ = () @staticmethod def encode_op_pushdata(d): @@ -361,8 +361,11 @@ def __init__(self, msg, data): self.data = data super(CScriptTruncatedPushDataError, self).__init__(msg) + # This is used, eg, for blockchain heights in coinbase scripts (bip34) -class CScriptNum(): +class CScriptNum: + __slots__ = ("value",) + def __init__(self, d=0): self.value = d @@ -393,6 +396,8 @@ class CScript(bytes): iter(script) however does iterate by opcode. """ + __slots__ = () + @classmethod def __coerce_instance(cls, other): # Coerce other into bytes From 17b42f4122740a7d9c91f3b42f77907e9cdcf680 Mon Sep 17 00:00:00 2001 From: Justin Turner Arthur Date: Tue, 25 Sep 2018 21:10:13 -0500 Subject: [PATCH 071/263] Check for specific tx acceptance failures based on script signature --- test/functional/p2p_segwit.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 1b3c5bd1fb..afbbfa8992 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -769,12 +769,16 @@ def test_p2sh_witness(self): # will require a witness to spend a witness program regardless of # segwit activation. Note that older bitcoind's that are not # segwit-aware would also reject this for failing CLEANSTACK. - test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) + with self.nodes[0].assert_debug_log( + expected_msgs=(spend_tx.hash, 'was not accepted: non-mandatory-script-verify-flag (Witness program was passed an empty witness)')): + test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) # Try to put the witness script in the scriptSig, should also fail. spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a']) spend_tx.rehash() - test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) + with self.nodes[0].assert_debug_log( + expected_msgs=('Not relaying invalid transaction {}'.format(spend_tx.hash), 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')): + test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) # Now put the witness script in the witness, should succeed after # segwit activates. From e46023287689fc8e79b9a82fe1a827d87c769423 Mon Sep 17 00:00:00 2001 From: Justin Turner Arthur Date: Wed, 26 Sep 2018 22:13:06 -0500 Subject: [PATCH 072/263] Document fixed attribute behavior in critical test framework classes. Per @jimmysong's suggestion in bitcoin/bitcoin#14305. Also corrects module for network objects and wrappers. --- test/functional/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/functional/README.md b/test/functional/README.md index 6929ab5991..d40052ac93 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -60,6 +60,11 @@ don't have test cases for. - When calling RPCs with lots of arguments, consider using named keyword arguments instead of positional arguments to make the intent of the call clear to readers. +- Many of the core test framework classes such as `CBlock` and `CTransaction` + don't allow new attributes to be added to their objects at runtime like + typical Python objects allow. This helps prevent unpredictable side effects + from typographical errors or usage of the objects outside of their intended + purpose. #### RPC and P2P definitions @@ -72,7 +77,7 @@ P2P messages. These can be found in the following source files: #### Using the P2P interface -- `mininode.py` contains all the definitions for objects that pass +- `messages.py` contains all the definitions for objects that pass over the network (`CBlock`, `CTransaction`, etc, along with the network-level wrappers for them, `msg_block`, `msg_tx`, etc). From ec1201a36847f7aa942eab1b3a3d082f6daf0031 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 15 Sep 2018 18:02:14 +0300 Subject: [PATCH 073/263] Don't use systray icon on inappropriate systems Prevent a user from losing access to the main window by minimizing it to the tray on some systems (e.g. GNOME 3.26+). --- src/qt/bitcoingui.cpp | 6 +++++- src/qt/optionsdialog.cpp | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 51aff08c42..4540fec4f7 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -131,7 +131,9 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty createToolBars(); // Create system tray icon and notification - createTrayIcon(networkStyle); + if (QSystemTrayIcon::isSystemTrayAvailable()) { + createTrayIcon(networkStyle); + } // Create status bar statusBar(); @@ -585,6 +587,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) { + assert(QSystemTrayIcon::isSystemTrayAvailable()); + #ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index b51322394f..c9871f6c66 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : @@ -126,6 +127,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : connect(ui->proxyIpTor, &QValidatedLineEdit::validationDidChange, this, &OptionsDialog::updateProxyValidationState); connect(ui->proxyPort, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState); connect(ui->proxyPortTor, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState); + + if (!QSystemTrayIcon::isSystemTrayAvailable()) { + ui->hideTrayIcon->setChecked(true); + ui->hideTrayIcon->setEnabled(false); + ui->minimizeToTray->setChecked(false); + ui->minimizeToTray->setEnabled(false); + } } OptionsDialog::~OptionsDialog() @@ -211,8 +219,10 @@ void OptionsDialog::setMapper() /* Window */ #ifndef Q_OS_MAC - mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon); - mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); + if (QSystemTrayIcon::isSystemTrayAvailable()) { + mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon); + mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); + } mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose); #endif From 430bf6c7a1a24a59050e7c9dac56b64b820edb43 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Fri, 28 Sep 2018 08:58:39 -0400 Subject: [PATCH 074/263] depends: fix bitcoin-qt back-compat with older freetype versions at runtime A few years ago, libfreetype introduced FT_Get_Font_Format() as an alias for FT_Get_X11_Font_Format(), but FT_Get_X11_Font_Format() was kept for abi backwards-compatibility. Our qt bump to 5.9 introduced a call to FT_Get_Font_Format(). Replace it with FT_Get_X11_Font_Format() in order to remain compatibile with older freetype, which is still used by e.g. Ubuntu Trusty. --- depends/packages/qt.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 5286f89c30..d15f147cd7 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -120,6 +120,7 @@ define $(package)_extract_cmds endef define $(package)_preprocess_cmds + sed -i.old "s|FT_Get_Font_Format|FT_Get_X11_Font_Format|" qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ From 0809e68a9084630ff4d11ec0503a3d0ab52bc6d7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 28 Sep 2018 17:27:21 +0200 Subject: [PATCH 075/263] doc: Add historical release notes for 0.14.3 and 0.15.2 Tree-SHA512: 56c4293a9536a3d6cf747c911cb605f5509707f0a43b19574e9c3038c6717465a69c9225cf654eb1f31ee6e8e2b319bb6ec537a4dc579775d087e96c432b245c --- doc/release-notes/release-notes-0.14.3.md | 118 ++++++++++++++++++++++ doc/release-notes/release-notes-0.15.2.md | 118 ++++++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 doc/release-notes/release-notes-0.14.3.md create mode 100644 doc/release-notes/release-notes-0.15.2.md diff --git a/doc/release-notes/release-notes-0.14.3.md b/doc/release-notes/release-notes-0.14.3.md new file mode 100644 index 0000000000..8259152f0b --- /dev/null +++ b/doc/release-notes/release-notes-0.14.3.md @@ -0,0 +1,118 @@ +Bitcoin Core version *0.14.3* is now available from: + + + +This is a new minor version release, including various bugfixes and +performance improvements. + +Please report bugs using the issue tracker at github: + + + +To receive security and update notifications, please subscribe to: + + + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +No attempt is made to prevent installing or running the software on Windows XP, you +can still do so at your own risk but be aware that there are known instabilities and issues. +Please do not report issues about Windows XP to the issue tracker. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notable changes +=============== + +Denial-of-Service vulnerability CVE-2018-17144 + ------------------------------- + +A denial-of-service vulnerability exploitable by miners has been discovered in +Bitcoin Core versions 0.14.0 up to 0.16.2. It is recommended to upgrade any of +the vulnerable versions to 0.14.3, 0.15.2 or 0.16.3 as soon as possible. + +Known Bugs +========== + +Since 0.14.0 the approximate transaction fee shown in Bitcoin-Qt when using coin +control and smart fee estimation does not reflect any change in target from the +smart fee slider. It will only present an approximate fee calculated using the +default target. The fee calculated using the correct target is still applied to +the transaction and shown in the final send confirmation dialog. + +0.14.3 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### Consensus +- #14247 `52965fb` Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar) + +### RPC and other APIs + +- #10445 `87a21d5` Fix: make CCoinsViewDbCursor::Seek work for missing keys (Pieter Wuille, Gregory Maxwell) +- #9853 Return correct error codes in setban(), fundrawtransaction(), removeprunedfunds(), bumpfee(), blockchain.cpp (John Newbery) + + +### P2P protocol and network code + +- #10234 `d289b56` [net] listbanned RPC and QT should show correct banned subnets (John Newbery) + +### Build system + + +### Miscellaneous + +- #10451 `3612219` contrib/init/bitcoind.openrcconf: Don't disable wallet by default (Luke Dashjr) +- #10250 `e23cef0` Fix some empty vector references (Pieter Wuille) +- #10196 `d28d583` PrioritiseTransaction updates the mempool tx counter (Suhas Daftuar) +- #9497 `e207342` Fix CCheckQueue IsIdle (potential) race condition and remove dangerous constructors. (Jeremy Rubin) + +### GUI + +- #9481 `7abe7bb` Give fallback fee a reasonable indent (Luke Dashjr) +- #9481 `3e4d7bf` Qt/Send: Figure a decent warning colour from theme (Luke Dashjr) +- #9481 `e207342` Show more significant warning if we fall back to the default fee (Jonas Schnelli) + +### Wallet + +- #10308 `28b8b8b` Securely erase potentially sensitive keys/values (tjps) +- #10265 `ff13f59` Make sure pindex is non-null before possibly referencing in LogPrintf call. (Karl-Johan Alm) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Cory Fields +- CryptAxe +- fanquake +- Jeremy Rubin +- John Newbery +- Jonas Schnelli +- Gregory Maxwell +- Karl-Johan Alm +- Luke Dashjr +- MarcoFalke +- Matt Corallo +- Mikerah +- Pieter Wuille +- practicalswift +- Suhas Daftuar +- Thomas Snider +- Tjps +- Wladimir J. van der Laan + +And to those that reported security issues: + +- awemany (for CVE-2018-17144, previously credited as "anonymous reporter") + diff --git a/doc/release-notes/release-notes-0.15.2.md b/doc/release-notes/release-notes-0.15.2.md new file mode 100644 index 0000000000..1f58279051 --- /dev/null +++ b/doc/release-notes/release-notes-0.15.2.md @@ -0,0 +1,118 @@ +Bitcoin Core version *0.15.2* is now available from: + + + +This is a new minor version release, including various bugfixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + + +To receive security and update notifications, please subscribe to: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0 or higher, your chainstate database will +be converted to a new format, which will take anywhere from a few minutes to +half an hour, depending on the speed of your machine. + +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15 or upgrade to version 0.15 will cause all fee +estimates to be discarded. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + + +Notable changes +=============== + +Denial-of-Service vulnerability CVE-2018-17144 +------------------------------- + +A denial-of-service vulnerability exploitable by miners has been discovered in +Bitcoin Core versions 0.14.0 up to 0.16.2. It is recommended to upgrade any of +the vulnerable versions to 0.15.2 or 0.16.3 as soon as possible. + +0.15.2 Change log +================= + +### Build system + +- #11995 `9bb1a16` depends: Fix Qt build with XCode 9.2(fanquake) +- #12946 `93b9a61` depends: Fix Qt build with XCode 9.3(fanquake) +- #13544 `9fd3e00` depends: Update Qt download url (fanquake) +- #11847 `cb7ef31` Make boost::multi_index comparators const (sdaftuar) + +### Consensus +- #14247 `4b8a3f5` Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar) + +### RPC +- #11676 `7af2457` contrib/init: Update openrc-run filename (Luke Dashjr) +- #11277 `7026845` Fix uninitialized URI in batch RPC requests (Russell Yanofsky) + +### Wallet +- #11289 `3f1db56` Wrap dumpwallet warning and note scripts aren't dumped (MeshCollider) +- #11289 `42ea47d` Add wallet backup text to import*, add* and dumpwallet RPCs (MeshCollider) +- #11590 `6372a75` [Wallet] always show help-line of wallet encryption calls (Jonas Schnelli) + +### bitcoin-tx + +- #11554 `a69cc07` Sanity-check script sizes in bitcoin-tx (TheBlueMatt) + +### Tests +- #11277 `3a6cdd4` Add test for multiwallet batch RPC calls (Russell Yanofsky) +- #11647 `1c8c7f8` Add missing batch rpc calls to python coverage logs (Russell Yanofsky) +- #11277 `1036c43` Add missing multiwallet rpc calls to python coverage logs (Russell Yanofsky) +- #11277 `305f768` Limit AuthServiceProxyWrapper.\_\_getattr\_\_ wrapping (Russell Yanofsky) +- #11277 `2eea279` Make AuthServiceProxy.\_batch method usable (Russell Yanofsky) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- fanquake +- Jonas Schnelli +- Luke Dashjr +- Matt Corallo +- MeshCollider +- Russell Yanofsky +- Suhas Daftuar +- Wladimir J. van der Laan + +And to those that reported security issues: + +- awemany (for CVE-2018-17144, previously credited as "anonymous reporter") + From 88a79cb436b30b39d37d139da723f5a31e9d161b Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Sat, 29 Sep 2018 22:09:15 -0400 Subject: [PATCH 076/263] fix converttopsbt permitsigdata arg, add basic test --- src/rpc/rawtransaction.cpp | 2 +- test/functional/rpc_psbt.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7397216506..e13a551388 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1669,7 +1669,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) // Remove all scriptSigs and scriptWitnesses from inputs for (CTxIn& input : tx.vin) { - if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && (request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool()))) { + if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && !permitsigdata) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Inputs must not have scriptSigs and scriptWitnesses"); } input.scriptSig.clear(); diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 54dc871448..3cbaa274e9 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -107,6 +107,9 @@ def run_test(self): # Make sure that a psbt with signatures cannot be converted signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex']) assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex']) + assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex'], False) + # Unless we allow it to convert and strip signatures + self.nodes[0].converttopsbt(signedtx['hex'], True) # Explicitly allow converting non-empty txs new_psbt = self.nodes[0].converttopsbt(rawtx['hex']) From 380c843217139b180457889699c65b37ae3b4a87 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sun, 5 Aug 2018 16:38:25 +0000 Subject: [PATCH 077/263] utils: Convert Windows args to utf-8 string --- src/bitcoin-cli.cpp | 5 +++++ src/bitcoind.cpp | 4 ++++ src/qt/bitcoin.cpp | 4 ++++ src/util.cpp | 32 ++++++++++++++++++++++++++++ src/util.h | 16 ++++++++++++++ test/functional/feature_uacomment.py | 2 +- 6 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 09507fd249..f466505114 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -511,6 +512,10 @@ static int CommandLineRPC(int argc, char *argv[]) int main(int argc, char* argv[]) { +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif SetupEnvironment(); if (!SetupNetworking()) { fprintf(stderr, "Error: Initializing networking failed\n"); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index bf04d95b50..18fcd9bc2a 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -185,6 +185,10 @@ static bool AppInit(int argc, char* argv[]) int main(int argc, char* argv[]) { +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif SetupEnvironment(); // Connect bitcoind signal handlers diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 1e950e2686..61a9f390e9 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -552,6 +552,10 @@ static void SetupUIArgs() #ifndef BITCOIN_QT_TEST int main(int argc, char *argv[]) { +#ifdef WIN32 + util::WinCmdLineArgs winArgs; + std::tie(argc, argv) = winArgs.get(); +#endif SetupEnvironment(); std::unique_ptr node = interfaces::MakeNode(); diff --git a/src/util.cpp b/src/util.cpp index fa624aee90..1002302904 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -61,6 +61,7 @@ #include #include /* for _commit */ +#include #include #endif @@ -1200,6 +1201,10 @@ void SetupEnvironment() } catch (const std::runtime_error&) { setenv("LC_ALL", "C", 1); } +#elif defined(WIN32) + // Set the default input/output charset is utf-8 + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); #endif // The path locale is lazy initialized and to avoid deinitialization errors // in multithreading environments, it is set explicitly by the main thread. @@ -1265,3 +1270,30 @@ int ScheduleBatchPriority() return 1; #endif } + +namespace util { +#ifdef WIN32 +WinCmdLineArgs::WinCmdLineArgs() +{ + wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); + std::wstring_convert, wchar_t> utf8_cvt; + argv = new char*[argc]; + args.resize(argc); + for (int i = 0; i < argc; i++) { + args[i] = utf8_cvt.to_bytes(wargv[i]); + argv[i] = &*args[i].begin(); + } + LocalFree(wargv); +} + +WinCmdLineArgs::~WinCmdLineArgs() +{ + delete[] argv; +} + +std::pair WinCmdLineArgs::get() +{ + return std::make_pair(argc, argv); +} +#endif +} // namespace util diff --git a/src/util.h b/src/util.h index f119385e48..fa6d2cd489 100644 --- a/src/util.h +++ b/src/util.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include // for boost::thread_interrupted @@ -361,6 +362,21 @@ inline void insert(std::set& dst, const Tsrc& src) { dst.insert(src.begin(), src.end()); } +#ifdef WIN32 +class WinCmdLineArgs +{ +public: + WinCmdLineArgs(); + ~WinCmdLineArgs(); + std::pair get(); + +private: + int argc; + char** argv; + std::vector args; +}; +#endif + } // namespace util #endif // BITCOIN_UTIL_H diff --git a/test/functional/feature_uacomment.py b/test/functional/feature_uacomment.py index 691a39b825..fb4ad21359 100755 --- a/test/functional/feature_uacomment.py +++ b/test/functional/feature_uacomment.py @@ -31,7 +31,7 @@ def run_test(self): self.nodes[0].assert_start_raises_init_error(["-uacomment=" + 'a' * 256], expected, match=ErrorMatch.FULL_REGEX) self.log.info("test -uacomment unsafe characters") - for unsafe_char in ['/', ':', '(', ')']: + for unsafe_char in ['/', ':', '(', ')', '₿', '🏃']: expected = "Error: User Agent comment \(" + re.escape(unsafe_char) + "\) contains unsafe characters." self.nodes[0].assert_start_raises_init_error(["-uacomment=" + unsafe_char], expected, match=ErrorMatch.FULL_REGEX) From 3f5ac2720520e9bce064ae6d28ba5f0488b2087a Mon Sep 17 00:00:00 2001 From: murrayn Date: Tue, 18 Sep 2018 02:12:16 -0700 Subject: [PATCH 078/263] Include some files currently missed by 'make distclean'. --- Makefile.am | 2 +- src/Makefile.test.include | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 10dda65b21..0b91e85f4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -294,5 +294,5 @@ clean-docs: clean-local: clean-docs rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP) - rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache + rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache share/rpcauth/__pycache__ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 269a6ff805..a5d93d1ad8 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -161,7 +161,7 @@ nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES) $(BITCOIN_TESTS): $(GENERATED_TEST_FILES) -CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) +CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) $(BITCOIN_TESTS:.cpp=.cpp.log) CLEANFILES += $(CLEAN_BITCOIN_TEST) From 4fb3388db95f408566e43ebb9736842cfbff0a7d Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 2 Oct 2018 20:33:31 -0400 Subject: [PATCH 079/263] check that a separator is found for psbt inputs, outputs, and global map --- src/script/sign.h | 30 +++++++++++++++++++++++++++--- test/functional/data/rpc_psbt.json | 3 ++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/script/sign.h b/src/script/sign.h index 2fc4575e59..5b45777a2d 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -300,6 +300,7 @@ struct PSBTInput template inline void Unserialize(Stream& s) { // Read loop + bool found_sep = false; while(!s.empty()) { // Read std::vector key; @@ -307,7 +308,10 @@ struct PSBTInput // the key is empty if that was actually a separator byte // This is a special case for key lengths 0 as those are not allowed (except for separator) - if (key.empty()) return; + if (key.empty()) { + found_sep = true; + break; + } // First byte of key is the type unsigned char type = key[0]; @@ -422,6 +426,10 @@ struct PSBTInput break; } } + + if (!found_sep) { + throw std::ios_base::failure("Separator is missing at the end of an input map"); + } } template @@ -475,6 +483,7 @@ struct PSBTOutput template inline void Unserialize(Stream& s) { // Read loop + bool found_sep = false; while(!s.empty()) { // Read std::vector key; @@ -482,7 +491,10 @@ struct PSBTOutput // the key is empty if that was actually a separator byte // This is a special case for key lengths 0 as those are not allowed (except for separator) - if (key.empty()) return; + if (key.empty()) { + found_sep = true; + break; + } // First byte of key is the type unsigned char type = key[0]; @@ -527,6 +539,10 @@ struct PSBTOutput } } } + + if (!found_sep) { + throw std::ios_base::failure("Separator is missing at the end of an output map"); + } } template @@ -602,6 +618,7 @@ struct PartiallySignedTransaction } // Read global data + bool found_sep = false; while(!s.empty()) { // Read std::vector key; @@ -609,7 +626,10 @@ struct PartiallySignedTransaction // the key is empty if that was actually a separator byte // This is a special case for key lengths 0 as those are not allowed (except for separator) - if (key.empty()) break; + if (key.empty()) { + found_sep = true; + break; + } // First byte of key is the type unsigned char type = key[0]; @@ -649,6 +669,10 @@ struct PartiallySignedTransaction } } + if (!found_sep) { + throw std::ios_base::failure("Separator is missing at the end of the global map"); + } + // Make sure that we got an unsigned tx if (!tx) { throw std::ios_base::failure("No unsigned transcation was provided"); diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index dd40a096de..57f2608ee9 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -17,7 +17,8 @@ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", - "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A" + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", + "cHNidP8BAHMCAAAAAbiWoY6pOQepFsEGhUPXaulX9rvye2NH+NrdlAHg+WgpAQAAAAD/////AkBLTAAAAAAAF6kUqWwXCcLM5BN2zoNqMNT5qMlIi7+HQEtMAAAAAAAXqRSVF/in2XNxAlN1OSxkyp0z+Wtg2YcAAAAAAAEBIBNssgAAAAAAF6kUamsvautR8hRlMRY6OKNTx03DK96HAQcXFgAUo8u1LWpHprjt/uENAwBpGZD0UH0BCGsCRzBEAiAONfH3DYiw67ZbylrsxCF/XXpVwyWBRgofyRbPslzvwgIgIKCsWw5sHSIPh1icNvcVLZLHWj6NA7Dk+4Os2pOnMbQBIQPGStfYHPtyhpV7zIWtn0Q4GXv5gK1zy/tnJ+cBXu4iiwABABYAFMwmJQEz+HDpBEEabxJ5PogPsqZRAAEAFgAUyCrGc3h3FYCmiIspbv2pSTKZ5jU" ], "valid" : [ "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA", From db01839361ae01201c27d3a96f6346d76a8314e0 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 3 Oct 2018 10:10:35 +0200 Subject: [PATCH 080/263] test: Add missing call to skip_if_no_cli() --- test/functional/test_framework/test_framework.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 97710bd6cd..7e2ec673df 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -161,8 +161,10 @@ def main(self): success = TestStatus.FAILED try: - if self.options.usecli and not self.supports_cli: - raise SkipTest("--usecli specified but test does not support using CLI") + if self.options.usecli: + if not self.supports_cli: + raise SkipTest("--usecli specified but test does not support using CLI") + self.skip_if_no_cli() self.skip_test_if_missing_module() self.setup_chain() self.setup_network() From 5aaf1a047320c3dc64a177af0c6b7a8c1a747fc2 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 3 Oct 2018 11:16:03 +0200 Subject: [PATCH 081/263] doc: Add historical release notes for 0.17.0 Tree-SHA512: 3b33d2e261b7c94a6556f55fa7854be06c4104276266e5af1870e815703a241c95b9508793ece4a91e447ade8b141326d1be965fdd6b3609a7aeec3127fab6e8 --- doc/release-notes/release-notes-0.17.0.md | 1108 +++++++++++++++++++++ 1 file changed, 1108 insertions(+) create mode 100644 doc/release-notes/release-notes-0.17.0.md diff --git a/doc/release-notes/release-notes-0.17.0.md b/doc/release-notes/release-notes-0.17.0.md new file mode 100644 index 0000000000..1b6e2f8e6c --- /dev/null +++ b/doc/release-notes/release-notes-0.17.0.md @@ -0,0 +1,1108 @@ +(note: this is a temporary file, to be added-to by anybody, and moved to +release-notes at release time) + +Bitcoin Core version 0.17.0 is now available from: + + + +This is a new major version release, including new features, various bugfixes +and performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + + +To receive security and update notifications, please subscribe to: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +If your node has a txindex, the txindex db will be migrated the first time you run 0.17.0 or newer, which may take up to a few hours. Your node will not be functional until this migration completes. + +The first time you run version 0.15.0 or newer, your chainstate database will be converted to a +new format, which will take anywhere from a few minutes to half an hour, +depending on the speed of your machine. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.10+, and Windows 7 and newer (Windows XP is not supported). + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +From 0.17.0 onwards macOS <10.10 is no longer supported. 0.17.0 is built using Qt 5.9.x, which doesn't +support versions of macOS older than 10.10. + +Known issues +============ + +- Upgrading from 0.13.0 or older currently results in memory blow-up during the roll-back of blocks to the SegWit activation point. In these cases, a full `-reindex` is necessary. + +- The GUI suffers from visual glitches in the new MacOS dark mode. This has to do with our Qt theme handling and is not a new problem in 0.17.0, but is expected to be resolved in 0.17.1. + +Notable changes +=============== + +Changed configuration options +----------------------------- + +- `-includeconf=` can be used to include additional configuration files. + Only works inside the `bitcoin.conf` file, not inside included files or from + command-line. Multiple files may be included. Can be disabled from command- + line via `-noincludeconf`. Note that multi-argument commands like + `-includeconf` will override preceding `-noincludeconf`, i.e. + ``` + noincludeconf=1 + includeconf=relative.conf + ``` + + as bitcoin.conf will still include `relative.conf`. + +GUI changes +----------- + +- Block storage can be limited under Preferences, in the Main tab. Undoing this setting requires downloading the full blockchain again. This mode is incompatible with -txindex and -rescan. + +External wallet files +--------------------- + +The `-wallet=` option now accepts full paths instead of requiring wallets +to be located in the -walletdir directory. + +Newly created wallet format +--------------------------- + +If `-wallet=` is specified with a path that does not exist, it will now +create a wallet directory at the specified location (containing a wallet.dat +data file, a db.log file, and database/log.?????????? files) instead of just +creating a data file at the path and storing log files in the parent +directory. This should make backing up wallets more straightforward than +before because the specified wallet path can just be directly archived without +having to look in the parent directory for transaction log files. + +For backwards compatibility, wallet paths that are names of existing data files +in the `-walletdir` directory will continue to be accepted and interpreted the +same as before. + +Dynamic loading and creation of wallets +--------------------------------------- + +Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load, create and unload wallets dynamically at runtime: + +- Existing wallets can be loaded by calling the `loadwallet` RPC. The wallet can be specified as file/directory basename (which must be located in the `walletdir` directory), or as an absolute path to a file/directory. +- New wallets can be created (and loaded) by calling the `createwallet` RPC. The provided name must not match a wallet file in the `walletdir` directory or the name of a wallet that is currently loaded. +- Loaded wallets can be unloaded by calling the `unloadwallet` RPC. + +This feature is currently only available through the RPC interface. + +Coin selection +-------------- + +### Partial spend avoidance + +When an address is paid multiple times the coins from those separate payments can be spent separately which hurts privacy due to linking otherwise separate addresses. A new `-avoidpartialspends` flag has been added (default=false). If enabled, the wallet will always spend existing UTXO to the same address together even if it results in higher fees. If someone were to send coins to an address after it was used, those coins will still be included in future coin selections. + +Configuration sections for testnet and regtest +---------------------------------------------- + +It is now possible for a single configuration file to set different +options for different networks. This is done by using sections or by +prefixing the option with the network, such as: + + main.uacomment=bitcoin + test.uacomment=bitcoin-testnet + regtest.uacomment=regtest + [main] + mempoolsize=300 + [test] + mempoolsize=100 + [regtest] + mempoolsize=20 + +If the following options are not in a section, they will only apply to mainnet: +`addnode=`, `connect=`, `port=`, `bind=`, `rpcport=`, `rpcbind=` and `wallet=`. +The options to choose a network (`regtest=` and `testnet=`) must be specified +outside of sections. + +'label' and 'account' APIs for wallet +------------------------------------- + +A new 'label' API has been introduced for the wallet. This is intended as a +replacement for the deprecated 'account' API. The 'account' can continue to +be used in V0.17 by starting bitcoind with the '-deprecatedrpc=accounts' +argument, and will be fully removed in V0.18. + +The label RPC methods mirror the account functionality, with the following functional differences: + +- Labels can be set on any address, not just receiving addresses. This functionality was previously only available through the GUI. +- Labels can be deleted by reassigning all addresses using the `setlabel` RPC method. +- There isn't support for sending transactions _from_ a label, or for determining which label a transaction was sent from. +- Labels do not have a balance. + +Here are the changes to RPC methods: + +| Deprecated Method | New Method | Notes | +| :---------------------- | :-------------------- | :-----------| +| `getaccount` | `getaddressinfo` | `getaddressinfo` returns a json object with address information instead of just the name of the account as a string. | +| `getaccountaddress` | n/a | There is no replacement for `getaccountaddress` since labels do not have an associated receive address. | +| `getaddressesbyaccount` | `getaddressesbylabel` | `getaddressesbylabel` returns a json object with the addresses as keys, instead of a list of strings. | +| `getreceivedbyaccount` | `getreceivedbylabel` | _no change in behavior_ | +| `listaccounts` | `listlabels` | `listlabels` does not return a balance or accept `minconf` and `watchonly` arguments. | +| `listreceivedbyaccount` | `listreceivedbylabel` | Both methods return new `label` fields, along with `account` fields for backward compatibility. | +| `move` | n/a | _no replacement_ | +| `sendfrom` | n/a | _no replacement_ | +| `setaccount` | `setlabel` | Both methods now:
  • allow assigning labels to any address, instead of raising an error if the address is not receiving address.
  • delete the previous label associated with an address when the final address using that label is reassigned to a different label, instead of making an implicit `getaccountaddress` call to ensure the previous label still has a receiving address. | + +| Changed Method | Notes | +| :--------------------- | :------ | +| `addmultisigaddress` | Renamed `account` named parameter to `label`. Still accepts `account` for backward compatibility if running with '-deprecatedrpc=accounts'. | +| `getnewaddress` | Renamed `account` named parameter to `label`. Still accepts `account` for backward compatibility. if running with '-deprecatedrpc=accounts' | +| `listunspent` | Returns new `label` fields. `account` field will be returned for backward compatibility if running with '-deprecatedrpc=accounts' | +| `sendmany` | The `account` named parameter has been renamed to `dummy`. If provided, the `dummy` parameter must be set to the empty string, unless running with the `-deprecatedrpc=accounts` argument (in which case functionality is unchanged). | +| `listtransactions` | The `account` named parameter has been renamed to `dummy`. If provided, the `dummy` parameter must be set to the string `*`, unless running with the `-deprecatedrpc=accounts` argument (in which case functionality is unchanged). | +| `getbalance` | `account`, `minconf` and `include_watchonly` parameters are deprecated, and can only be used if running with '-deprecatedrpc=accounts' | + +BIP 174 Partially Signed Bitcoin Transactions support +----------------------------------------------------- + +[BIP 174 PSBT](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) 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. He constructs + 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. +- A potentially other Updater adds 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. 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. + +### 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. + +Upgrading non-HD wallets to HD wallets +-------------------------------------- + +Since Bitcoin Core 0.13.0, creating new BIP 32 Hierarchical Deterministic wallets has been supported by Bitcoin Core but old non-HD wallets could not be upgraded to HD. Now non-HD wallets can be upgraded to HD using the `-upgradewallet` command line option. This upgrade will result in the all keys in the keypool being marked as used and a new keypool generated. **A new backup must be made when this upgrade is performed.** + +Additionally, `-upgradewallet` can be used to upgraded from a non-split HD chain (all keys generated with `m/0'/0'/i'`) to a split HD chain (receiving keys generated with `'m/0'/0'/i'` and change keys generated with `m'/0'/1'/i'`). When this upgrade occurs, all keys already in the keypool will remain in the keypool to be used until all keys from before the upgrade are exhausted. This is to avoid issues with backups and downgrades when some keys may come from the change key keypool. Users can begin using the new split HD chain keypools by using the `newkeypool` RPC to mark all keys in the keypool as used and begin using a new keypool generated from the split HD chain. + +HD Master key rotation +---------------------- + +A new RPC, `sethdseed`, has been introduced which allows users to set a new HD seed or set their own HD seed. This allows for a new HD seed to be used. **A new backup must be made when a new HD seed is set.** + +Low-level RPC changes +--------------------- + +- The new RPC `scantxoutset` can be used to scan the UTXO set for entries + that match certain output descriptors. Refer to the [output descriptors + reference documentation](doc/descriptors.md) for more details. This call + is similar to `listunspent` but does not use a wallet, meaning that the + wallet can be disabled at compile or run time. This call is experimental, + as such, is subject to changes or removal in future releases. + +- The `createrawtransaction` RPC will now accept an array or dictionary (kept for compatibility) for the `outputs` parameter. This means the order of transaction outputs can be specified by the client. +- The `fundrawtransaction` RPC will reject the previously deprecated `reserveChangeKey` option. +- `sendmany` now shuffles outputs to improve privacy, so any previously expected behavior with regards to output ordering can no longer be relied upon. +- The new RPC `testmempoolaccept` can be used to test acceptance of a transaction to the mempool without adding it. +- JSON transaction decomposition now includes a `weight` field which provides + the transaction's exact weight. This is included in REST /rest/tx/ and + /rest/block/ endpoints when in json mode. This is also included in `getblock` + (with verbosity=2), `listsinceblock`, `listtransactions`, and + `getrawtransaction` RPC commands. +- New `fees` field introduced in `getrawmempool`, `getmempoolancestors`, `getmempooldescendants` and + `getmempoolentry` when verbosity is set to `true` with sub-fields `ancestor`, `base`, `modified` + and `descendant` denominated in BTC. This new field deprecates previous fee fields, such as + `fee`, `modifiedfee`, `ancestorfee` and `descendantfee`. +- The new RPC `getzmqnotifications` returns information about active ZMQ + notifications. +- When bitcoin is not started with any `-wallet=` options, the name of + the default wallet returned by `getwalletinfo` and `listwallets` RPCs is + now the empty string `""` instead of `"wallet.dat"`. If bitcoin is started + with any `-wallet=` options, there is no change in behavior, and the + name of any wallet is just its `` string. +- Passing an empty string (`""`) as the `address_type` parameter to + `getnewaddress`, `getrawchangeaddress`, `addmultisigaddress`, + `fundrawtransaction` RPCs is now an error. Previously, this would fall back + to using the default address type. It is still possible to pass null or leave + the parameter unset to use the default address type. + +- Bare multisig outputs to our keys are no longer automatically treated as + incoming payments. As this feature was only available for multisig outputs for + which you had all private keys in your wallet, there was generally no use for + them compared to single-key schemes. Furthermore, no address format for such + outputs is defined, and wallet software can't easily send to it. These outputs + will no longer show up in `listtransactions`, `listunspent`, or contribute to + your balance, unless they are explicitly watched (using `importaddress` or + `importmulti` with hex script argument). `signrawtransaction*` also still + works for them. + +- The `getwalletinfo` RPC method now returns an `hdseedid` value, which is always the same as the incorrectly-named `hdmasterkeyid` value. `hdmasterkeyid` will be removed in V0.18. +- The `getaddressinfo` RPC method now returns an `hdseedid` value, which is always the same as the incorrectly-named `hdmasterkeyid` value. `hdmasterkeyid` will be removed in V0.18. + +- Parts of the `validateaddress` RPC method have been deprecated and moved to + `getaddressinfo`. Clients must transition to using `getaddressinfo` to access + this information before upgrading to v0.18. The following deprecated fields + have moved to `getaddressinfo` and will only be shown with + `-deprecatedrpc=validateaddress`: `ismine`, `iswatchonly`, `script`, `hex`, + `pubkeys`, `sigsrequired`, `pubkey`, `addresses`, `embedded`, `iscompressed`, + `account`, `timestamp`, `hdkeypath`, `hdmasterkeyid`. +- `signrawtransaction` is deprecated and will be fully removed in v0.18. To use + `signrawtransaction` in v0.17, restart bitcoind with + `-deprecatedrpc=signrawtransaction`. Projects should transition to using + `signrawtransactionwithkey` and `signrawtransactionwithwallet` before + upgrading to v0.18. + +Other API changes +----------------- + +- The `inactivehdmaster` property in the `dumpwallet` output has been corrected to `inactivehdseed` + +### Logging + +- The log timestamp format is now ISO 8601 (e.g. "2018-02-28T12:34:56Z"). + +- When running bitcoind with `-debug` but without `-daemon`, logging to stdout + is now the default behavior. Setting `-printtoconsole=1` no longer implicitly + disables logging to debug.log. Instead, logging to file can be explicitly disabled + by setting `-debuglogfile=0`. + +Transaction index changes +------------------------- + +The transaction index is now built separately from the main node procedure, +meaning the `-txindex` flag can be toggled without a full reindex. If bitcoind +is run with `-txindex` on a node that is already partially or fully synced +without one, the transaction index will be built in the background and become +available once caught up. When switching from running `-txindex` to running +without the flag, the transaction index database will *not* be deleted +automatically, meaning it could be turned back on at a later time without a full +resync. + +Miner block size removed +------------------------ + +The `-blockmaxsize` option for miners to limit their blocks' sizes was +deprecated in V0.15.1, and has now been removed. Miners should use the +`-blockmaxweight` option if they want to limit the weight of their blocks. + +Python Support +-------------- + +Support for Python 2 has been discontinued for all test files and tools. + +0.17.0 change log +================= + +### Consensus +- #12204 `3fa24bb` Fix overly eager BIP30 bypass (morcos) + +### Policy +- #12568 `ed6ae80` Allow dustrelayfee to be set to zero (luke-jr) +- #13120 `ca2a233` Treat segwit as always active (MarcoFalke) +- #13096 `062738c` Fix `MAX_STANDARD_TX_WEIGHT` check (jl2012) + +### Mining +- #12693 `df529dc` Remove unused variable in SortForBlock (drewx2) +- #12448 `84efa9a` Interrupt block generation on shutdown request (promag) + +### Block and transaction handling +- #12225 `67447ba` Mempool cleanups (sdaftuar) +- #12356 `fd65937` Fix 'mempool min fee not met' debug output (Empact) +- #12287 `bf3353d` Optimise lock behaviour for GuessVerificationProgress() (jonasschnelli) +- #11889 `47a7666` Drop extra script variable in ProduceSignature (ryanofsky) +- #11880 `d59b8d6` Stop special-casing phashBlock handling in validation for TBV (TheBlueMatt) +- #12431 `947c25e` Only call NotifyBlockTip when chainActive changes (jamesob) +- #12653 `534b8fa` Allow to optional specify the directory for the blocks storage (jonasschnelli) +- #12172 `3b62a91` Bugfix: RPC: savemempool: Don't save until LoadMempool() is finished (jtimon) +- #12167 `88430cb` Make segwit failure due to `CLEANSTACK` violation return a `SCRIPT_ERR_CLEANSTACK` error code (maaku) +- #12561 `24133b1` Check for block corruption in ConnectBlock() (sdaftuar) +- #11617 `1b5723e` Avoid lock: Call FlushStateToDisk(…) regardless of fCheckForPruning (practicalswift) +- #11739 `0a8b7b4` Enforce `SCRIPT_VERIFY_P2SH` and `SCRIPT_VERIFY_WITNESS` from genesis (sdaftuar) +- #12885 `a49381d` Reduce implementation code inside CScript (sipa) +- #13032 `34dd1a6` Output values for "min relay fee not met" error (kristapsk) +- #13033 `a07e8ca` Build txindex in parallel with validation (jimpo) +- #13080 `66cc47b` Add compile time checking for ::mempool.cs runtime locking assertions (practicalswift) +- #13185 `08c1caf` Bugfix: the end of a reorged chain is invalid when connect fails (sipa) +- #11689 `0264836` Fix missing locking in CTxMemPool::check(…) and CTxMemPool::setSanityCheck(…) (practicalswift) +- #13011 `3c2a41a` Cache witness hash in CTransaction (MarcoFalke) +- #13191 `0de7cc8` Specialized double-SHA256 with 64 byte inputs with SSE4.1 and AVX2 (sipa) +- #13243 `ea263e1` Make reusable base class for auxiliary indices (jimpo) +- #13393 `a607d23` Enable double-SHA256-for-64-byte code on 32-bit x86 (sipa) +- #13428 `caabdea` validation: check the specified number of blocks (off-by-one) (kallewoof) +- #13438 `450055b` Improve coverage of SHA256 SelfTest code (sipa) +- #13431 `954f4a9` validation: count blocks correctly for check level < 3 (kallewoof) +- #13386 `3a3eabe` SHA256 implementations based on Intel SHA Extensions (sipa) +- #11658 `9a1ad2c` During IBD, when doing pruning, prune 10% extra to avoid pruning again soon after (luke-jr) +- #13794 `8ce55df` chainparams: Update with data from assumed valid chain (MarcoFalke) +- #13527 `e7ea858` Remove promiscuousmempoolflags (MarcoFalke) + +### P2P protocol and network code +- #12342 `eaeaa2d` Extend #11583 ("Do not make it trivial for inbound peers to generate log entries") to include "version handshake timeout" message (clemtaylor) +- #12218 `9a32114` Move misbehaving logging to net logging category (laanwj) +- #10387 `5c2aff8` Eventually connect to `NODE_NETWORK_LIMITED` peers (jonasschnelli) +- #9037 `a36834f` Add test-before-evict discipline to addrman (EthanHeilman) +- #12622 `e1d6e2a` Correct addrman logging (laanwj) +- #11962 `0a01843` add seed.bitcoin.sprovoost.nl to DNS seeds (Sjors) +- #12569 `23e7fe8` Increase signal-to-noise ratio in debug.log by adjusting log level when logging failed non-manual connect():s (practicalswift) +- #12855 `c199869` Minor accumulated cleanups (tjps) +- #13153 `ef46c99` Add missing newlines to debug logging (laanwj) +- #13162 `a174702` Don't incorrectly log that REJECT messages are unknown (jnewbery) +- #13151 `7f4db9a` Serve blocks directly from disk when possible (laanwj) +- #13134 `70d3541` Add option `-enablebip61` to configure sending of BIP61 notifications (laanwj) +- #13532 `7209fec` Log warning when deprecated network name 'tor' is used (wodry) +- #13615 `172f984` Remove unused interrupt from SendMessages (fanquake) +- #13417 `1e90862` Tighten scope in `net_processing` (skeees) +- #13298 `f8d470e` Bucketing INV delays (1 bucket) for incoming connections to hide tx time (naumenkogs) +- #13672 `0d8d6be` Modified `in_addr6` cast in CConman class to work with msvc (sipsorcery) +- #11637 `c575260` Remove dead service bits code (MarcoFalke) +- #13212 `a6f00ce` Fixed a race condition when disabling the network (lmanners) +- #13656 `1211b15` Remove the boost/algorithm/string/predicate.hpp dependency (251Labs) +- #13423 `f58674a` Thread safety annotations in `net_processing` (skeees) +- #13776 `7d36237` Add missing verification of IPv6 address in CNetAddr::GetIn6Addr(…) (practicalswift) +- #13907 `48bf8ff` Introduce a maximum size for locators (gmaxwell) +- #13951 `8a9ffec` Hardcoded seeds update pre-0.17 branch (laanwj) + +### Wallet +- #12330 `2a30e67` Reduce scope of `cs_main` and `cs_wallet` locks in listtransactions (promag) +- #12298 `a1ffddb` Refactor HaveKeys to early return on false result (promag) +- #12282 `663911e` Disallow abandon of conflicted txes (MarcoFalke) +- #12333 `d405bee` Make CWallet::ListCoins atomic (promag) +- #12296 `8e6f9f4` Only fee-bump non-conflicted/non-confirmed txes (MarcoFalke) +- #11866 `6bb9c13` Do not un-mark fInMempool on wallet txn if ATMP fails (TheBlueMatt) +- #11882 `987a809` Disable default fallbackfee on mainnet (jonasschnelli) +- #9991 `4ca7c1e` listreceivedbyaddress Filter Address (NicolasDorier) +- #11687 `98bc27f` External wallet files (ryanofsky) +- #12658 `af88094` Sanitize some wallet serialization (sipa) +- #9680 `6acd870` Unify CWalletTx construction (ryanofsky) +- #10637 `e057589` Coin Selection with Murch's algorithm (achow101, Xekyo) +- #12408 `c39dd2e` Change output type globals to members (MarcoFalke) +- #12694 `9552dfb` Actually disable BnB when there are preset inputs (achow101) +- #11536 `cead84b` Rename account to label where appropriate (ryanofsky) +- #12709 `02b7e83` shuffle sendmany recipients ordering (instagibbs) +- #12699 `c948dc8` Shuffle transaction inputs before signing (instagibbs) +- #10762 `6d53663` Remove Wallet dependencies from init.cpp (jnewbery) +- #12857 `821980c` Avoid travis lint-include-guards error (ken2812221) +- #12702 `dab0d68` importprivkey: hint about importmulti (kallewoof) +- #12836 `9abdb7c` Make WalletInitInterface and DummyWalletInit private, fix nullptr deref (promag) +- #12785 `215158a` Initialize `m_last_block_processed` to nullptr (practicalswift) +- #12932 `8d651ae` Remove redundant lambda function arg in handleTransactionChanged (laanwj) +- #12749 `a84b056` feebumper: discard change outputs below discard rate (instagibbs) +- #12892 `9b3370d` introduce 'label' API for wallet (jnewbery) +- #12925 `6d3de17` Logprint the start of a rescan (jonasschnelli) +- #12888 `39439e5` debug log number of unknown wallet records on load (instagibbs) +- #12977 `434150a` Refactor `g_wallet_init_interface` to const reference (promag) +- #13017 `65d7083` Add wallets management functions (promag) +- #12953 `d1d54ae` Deprecate accounts (jnewbery) +- #12909 `476cb35` Make fee settings to be non-static members (MarcoFalke) +- #13002 `487dcbe` Do not treat bare multisig outputs as IsMine unless watched (sipa) +- #13028 `783bb64` Make vpwallets usage thread safe (promag) +- #12507 `2afdc29` Interrupt rescan on shutdown request (promag) +- #12729 `979150b` Get rid of ambiguous OutputType::NONE value (ryanofsky) +- #13079 `5778d44` Fix rescanblockchain rpc to properly report progress (Empact) +- #12560 `e03c0db` Upgrade path for non-HD wallets to HD (achow101) +- #13161 `7cc1bd3` Reset BerkeleyDB handle after connection fails (real-or-random) +- #13081 `0dec5b5` Add compile time checking for `cs_wallet` runtime locking assertions (practicalswift) +- #13127 `19a3a9e` Add Clang thread safety annotations for variables guarded by `cs_db` (practicalswift) +- #10740 `4cfe17c` `loadwallet` RPC - load wallet at runtime (jnewbery) +- #12924 `6738813` Fix hdmaster-key / seed-key confusion (scripted diff) (jnewbery) +- #13297 `d82c5d1` Fix incorrect comment for DeriveNewSeed (jnewbery) +- #13063 `6378eef` Use shared pointer to retain wallet instance (promag) +- #13142 `56fe3dc` Separate IsMine from solvability (sipa) +- #13194 `fd96d54` Remove template matching and pseudo opcodes (sipa) +- #13252 `c4cc8d9` Refactor ReserveKeyFromKeyPool for safety (Empact) +- #13058 `343d4e4` `createwallet` RPC - create new wallet at runtime (jnewbery) +- #13351 `2140f6c` Prevent segfault when sending to unspendable witness (MarcoFalke) +- #13060 `3f0f394` Remove getlabeladdress RPC (jnewbery) +- #13111 `000abbb` Add unloadwallet RPC (promag) +- #13160 `868cf43` Unlock spent outputs (promag) +- #13498 `f54f373` Fixups from account API deprecation (jnewbery) +- #13491 `61a044a` Improve handling of INVALID in IsMine (sipa) +- #13425 `028b0d9` Moving final scriptSig construction from CombineSignatures to ProduceSignature (PSBT signer logic) (achow101) +- #13564 `88a15eb` loadwallet shouldn't create new wallets (jnewbery) +- #12944 `619cd29` ScanforWalletTransactions should mark input txns as dirty (instagibbs) +- #13630 `d6b2235` Drop unused pindexRet arg to CMerkleTx::GetDepthInMainChain (Empact) +- #13566 `ad552a5` Fix get balance (jnewbery) +- #13500 `4a3e8c5` Decouple wallet version from client version (achow101) +- #13712 `aba2e66` Fix non-determinism in ParseHDKeypath(…). Avoid using an uninitialized variable in path calculation (practicalswift) +- #9662 `6b6e854` Add createwallet "disableprivatekeys" option: a sane mode for watchonly-wallets (jonasschnelli) +- #13683 `e8c7434` Introduce assertion to document the assumption that cache and cache_used are always set in tandem (practicalswift) +- #12257 `5f7575e` Use destination groups instead of coins in coin select (kallewoof) +- #13773 `89a116d` Fix accidental use of the comma operator (practicalswift) +- #13805 `c88529a` Correctly limit output group size (sdaftuar) +- #12992 `26f59f5` Add wallet name to log messages (PierreRochard) +- #13667 `b81a8a5` Fix backupwallet for multiwallets (domob1812) +- #13657 `51c693d` assert to ensure accuracy of CMerkleTx::GetBlocksToMaturity (Empact) +- #13812 `9d86aad` sum ancestors rather than taking max in output groups (kallewoof) +- #13876 `8eb9870` Catch `filesystem_error` and raise `InitError` (MarcoFalke) +- #13808 `13d51a2` shuffle coins before grouping, where warranted (kallewoof) +- #13666 `2115cba` Always create signatures with Low R values (achow101) +- #13917 `0333914` Additional safety checks in PSBT signer (sipa) +- #13968 `65e7a8b` couple of walletcreatefundedpsbt fixes (instagibbs) +- #14055 `2307a6e` fix walletcreatefundedpsbt deriv paths, add test (instagibbs) + +### RPC and other APIs +- #12336 `3843780` Remove deprecated rpc options (jnewbery) +- #12193 `5dc00f6` Consistently use UniValue.pushKV instead of push_back(Pair()) (karel-3d) (MarcoFalke) +- #12409 `0cc45ed` Reject deprecated reserveChangeKey in fundrawtransaction (MarcoFalke) +- #10583 `8a98dfe` Split part of validateaddress into getaddressinfo (achow101) +- #10579 `ffc6e48` Split signrawtransaction into wallet and non-wallet RPC command (achow101) +- #12494 `e4ffcac` Declare CMutableTransaction a struct in rawtransaction.h (Empact) +- #12503 `0e26591` createmultisig no longer takes addresses (instagibbs) +- #12083 `228b086` Improve getchaintxstats test coverage (promag) +- #12479 `cd5e438` Add child transactions to getrawmempool verbose output (conscott) +- #11872 `702e8b7` createrawtransaction: Accept sorted outputs (MarcoFalke) +- #12700 `ebdf84c` Document RPC method aliasing (ryanofsky) +- #12727 `8ee5c7b` Remove unreachable help conditions in rpcwallet.cpp (lutangar) +- #12778 `b648974` Add username and ip logging for RPC method requests (GabrielDav) +- #12717 `ac898b6` rest: Handle utxo retrieval when ignoring the mempool (romanz) +- #12787 `cd99e5b` Adjust ifdef to avoid unreachable code (practicalswift) +- #11742 `18815b4` Add testmempoolaccept (MarcoFalke) +- #12942 `fefb817` Drop redundant testing of signrawtransaction prevtxs args (Empact) +- #11200 `5f2a399` Allow for aborting rescans in the GUI (achow101) +- #12791 `3a8a4dc` Expose a transaction's weight via RPC (TheBlueMatt) +- #12436 `6e67754` Adds a functional test to validate the transaction version number in the RPC output (251Labs) +- #12240 `6f8b345` Introduced a new `fees` structure that aggregates all sub-field fee types denominated in BTC (mryandao) +- #12321 `eac067a` p2wsh and p2sh-p2wsh address in decodescript (fivepiece) +- #13090 `17266a1` Remove Safe mode (achow101, laanwj) +- #12639 `7eb7076` Reduce `cs_main` lock in listunspent (promag) +- #10267 `7b966d9` New -includeconf argument for including external configuration files (kallewoof) +- #10757 `b9551d3` Introduce getblockstats to plot things (jtimon) +- #13288 `a589f53` Remove the need to include rpc/blockchain.cpp in order to put `GetDifficulty` under test (Empact) +- #13394 `e1f8dce` cli: Ignore libevent warnings (theuni) +- #13439 `3f398d7` Avoid "duplicate" return value for invalid submitblock (TheBlueMatt) +- #13570 `a247594` Add new "getzmqnotifications" method (domob1812) +- #13072 `b25a4c2` Update createmultisig RPC to support segwit (ajtowns) +- #12196 `8fceae0` Add scantxoutset RPC method (jonasschnelli) +- #13557 `b654723` BIP 174 PSBT Serializations and RPCs (achow101) +- #13697 `f030410` Support output descriptors in scantxoutset (sipa) +- #13927 `bced8ea` Use pushKV in some new PSBT RPCs (domob1812) +- #13918 `a9c56b6` Replace median fee rate with feerate percentiles in getblockstats (marcinja) +- #13721 `9f23c16` Bugfixes for BIP 174 combining and deserialization (achow101) +- #13960 `517010e` Fix PSBT deserialization of 0-input transactions (achow101) + +### GUI +- #12416 `c997f88` Fix Windows build errors introduced in #10498 (practicalswift) +- #11733 `e782099` Remove redundant locks (practicalswift) +- #12426 `bfa3911` Initialize members in WalletModel (MarcoFalke) +- #12489 `e117cfe` Bugfix: respect user defined configuration file (-conf) in QT settings (jonasschnelli) +- #12421 `be263fa` navigate to transaction history page after send (Sjors) +- #12580 `ce56fdd` Show a transaction's virtual size in its details dialog (dooglus) +- #12501 `c8ea91a` Improved "custom fee" explanation in tooltip (randolf) +- #12616 `cff95a6` Set modal overlay hide button as default (promag) +- #12620 `8a43bdc` Remove TransactionTableModel::TxIDRole (promag) +- #12080 `56cc022` Add support to search the address book (promag) +- #12621 `2bac3e4` Avoid querying unnecessary model data when filtering transactions (promag) +- #12721 `e476826` remove "new" button during receive-mode in addressbook (jonasschnelli) +- #12723 `310dc61` Qt5: Warning users about invalid-BIP21 URI bitcoin:// (krab) +- #12610 `25cf18f` Multiwallet for the GUI (jonasschnelli) +- #12779 `f4353da` Remove unused method setupAmountWidget(…) (practicalswift) +- #12795 `68484d6` do not truncate .dat extension for wallets in gui (instagibbs) +- #12870 `1d54004` make clean removes `src/qt/moc_` files (Sjors) +- #13055 `bdda14d` Don't log to console by default (laanwj) +- #13141 `57c57df` fixes broken link on readme (marcoagner) +- #12928 `ef006d9` Initialize non-static class members that were previously neither initialized where defined nor in constructor (practicalswift) +- #13158 `81c533c` Improve sendcoinsdialog readability (marcoagner) +- #11491 `40c34a0` Add proxy icon in statusbar (mess110) +- #13264 `2a7c53b` Satoshi unit (GreatSock) +- #13097 `e545503` Support wallets loaded dynamically (promag) +- #13284 `f8be434` fix visual "overflow" of amount input (brandonrninefive) +- #13275 `a315b79` use `[default wallet]` as name for wallet with no name (jonasschnelli) +- #13273 `3fd0c23` Qt/Bugfix: fix handling default wallet with no name (jonasschnelli) +- #13341 `25d2df2` Stop translating command line options (laanwj) +- #13043 `6e249e4` OptionsDialog: add prune setting (Sjors) +- #13506 `6579d80` load wallet in UI after possible init aborts (jonasschnelli) +- #13458 `dc53f7f` Drop qt4 support (laanwj) +- #13528 `b877c39` Move BitcoinGUI initializers to class, fix initializer order warning (laanwj) +- #13536 `baf3a3a` coincontrol: Remove unused qt4 workaround (MarcoFalke) +- #13537 `10ffca7` Peer table: Visualize inbound/outbound state for every row (wodry) +- #13791 `2c14c1f` Reject dialogs if key escape is pressed (promag) + +### Build system +- #12371 `c9ca4f6` Add gitian PGP key: akx20000 (ghost) +- #11966 `f4f4f51` clientversion: Use full commit hash for commit-based version descriptions (luke-jr) +- #12417 `ae0fbf0` Upgrade `mac_alias` to 2.0.7 (droark) +- #12444 `1f055ef` gitian: Bump descriptors for (0.)17 (theuni) +- #12402 `59e032b` expat 2.2.5, ccache 3.4.1, miniupnpc 2.0.20180203 (fanquake) +- #12029 `daa84b3` Add a makefile target for Doxygen documentation (Ov3rlo4d) +- #12466 `6645eaf` Only use `D_DARWIN_C_SOURCE` when building miniupnpc on darwin (fanquake) +- #11986 `765a3eb` zeromq 4.2.3 (fanquake) +- #12373 `f13d756` Add build support for profiling (murrayn) +- #12631 `a312e20` gitian: Alphabetize signing keys & add kallewoof key (kallewoof) +- #12607 `29fad97` Remove ccache (fanquake) +- #12625 `c4219ff` biplist 1.0.3 (fanquake) +- #12666 `05042d3` configure: UniValue 1.0.4 is required for pushKV(, bool) (luke-jr) +- #12678 `6324c68` Fix a few compilation issues with Clang 7 and -Werror (vasild) +- #12692 `de6bdfd` Add configure options for various -fsanitize flags (eklitzke) +- #12901 `7e23972` Show enabled sanitizers in configure output (practicalswift) +- #12899 `3076993` macOS: Prevent Xcode 9.3 build warnings (AkioNak) +- #12715 `8fd6243` Add 'make clean' rule (hkjn) +- #13133 `a024a18` Remove python2 from configure.ac (ken2812221) +- #13005 `cb088b1` Make --enable-debug to pick better options (practicalswift) +- #13254 `092b366` Remove improper `qt/moc_*` cleaning glob from the general Makefile (Empact) +- #13306 `f5a7733` split warnings out of CXXFLAGS (theuni) +- #13385 `7c7508c` Guard against accidental introduction of new Boost dependencies (practicalswift) +- #13041 `5779dc4` Add linter checking for accidental introduction of locale dependence (practicalswift) +- #13408 `70a03c6` crypto: cleanup sha256 build (theuni) +- #13435 `cf7ca60` When build fails due to lib missing, indicate which one (Empact) +- #13445 `8eb76f3` Reset default -g -O2 flags when enable debug (ken2812221) +- #13465 `81069a7` Avoid concurrency issue when make multiple target (ken2812221) +- #13454 `45c00f8` Make sure `LC_ALL=C` is set in all shell scripts (practicalswift) +- #13480 `31145a3` Avoid copies in range-for loops and add a warning to detect them (theuni) +- #13486 `66e1a08` Move rpc/util.cpp from libbitcoin-util to libbitcoin-server (ken2812221) +- #13580 `40334c7` Detect if char equals `int8_t` (ken2812221) +- #12788 `287e4ed` Tune wildcards for LIBSECP256K1 target (kallewoof) +- #13611 `b55f0c3` bugfix: Use `__cpuid_count` for gnu C to avoid gitian build fail (ken2812221) +- #12971 `a6d14b1` Upgrade Qt to 5.9.6 (TheCharlatan) +- #13543 `6c6a300` Add RISC-V support (laanwj) +- #13177 `dcb154e` GCC-7 and glibc-2.27 back compat code (ken2812221) +- #13659 `90b1c7e` add missing leveldb defines (theuni) +- #13368 `c0f1569` Update gitian-build.sh for docker (achow101) +- #13171 `19d8ca5` Change gitian-descriptors to use bionic instead (ken2812221) +- #13604 `75bea05` Add depends 32-bit arm support for bitcoin-qt (TheCharlatan) +- #13623 `9cdb19f` Migrate gitian-build.sh to python (ken2812221) +- #13689 `8c36432` disable Werror when building zmq (greenaddress) +- #13617 `cf7f9ae` release: Require macos 10.10+ (fanquake) +- #13750 `c883653` use MacOS friendly sed syntax in qt.mk (Sjors) +- #13095 `415f2bf` update `ax_boost_chrono`/`unit_test_framework` (fanquake) +- #13732 `e8ffec6` Fix Qt's rcc determinism (Fuzzbawls) +- #13782 `8284f1d` Fix osslsigncode compile issue in gitian-build (ken2812221) +- #13696 `2ab7208` Add aarch64 qt depends support for cross compiling bitcoin-qt (TheCharlatan) +- #13705 `b413ba0` Add format string linter (practicalswift) +- #14000 `48c8459` fix qt determinism (theuni) +- #14018 `3e4829a` Bugfix: NSIS: Exclude `Makefile*` from docs (luke-jr) +- #12906 `048ac83` Avoid `interface` keyword to fix windows gitian build (ryanofsky) +- #13314 `a9b6957` Fix FreeBSD build by including utilstrencodings.h (laanwj) + +### Tests and QA +- #12252 `8d57319` Require all tests to follow naming convention (ajtowns) +- #12295 `935eb8d` Enable flake8 warnings for all currently non-violated rules (practicalswift) +- #11858 `b4d8549` Prepare tests for Windows (MarcoFalke) +- #11771 `2dbc4a4` Change invalidtxrequest to use BitcoinTestFramework (jnewbery) +- #12200 `d09968f` Bind functional test nodes to 127.0.0.1 (Sjors) +- #12425 `26dc2da` Add some script tests (richardkiss) +- #12455 `23481fa` Fix bip68 sequence test to reflect updated rpc error message (Empact) +- #12477 `acd1e61` Plug memory leaks and stack-use-after-scope (MarcoFalke) +- #12443 `07090c5` Move common args to bitcoin.conf (MarcoFalke) +- #12570 `39dcac2` Add test cases for HexStr (`std::reverse_iterator` and corner cases) (kostaz) +- #12582 `6012f1c` Fix ListCoins test failure due to unset `g_wallet_allow_fallback_fee` (ryanofsky) +- #12516 `7f99964` Avoid unintentional unsigned integer wraparounds in tests (practicalswift) +- #12512 `955fd23` Don't test against the mempool min fee information in mempool_limit.py (Empact) +- #12600 `29088b1` Add a test for large tx output scripts with segwit input (richardkiss) +- #12627 `791c3ea` Fix some tests to work on native windows (MarcoFalke) +- #12405 `0f58d7f` travis: Full clone for git subtree check (MarcoFalke) +- #11772 `0630974` Change invalidblockrequest to use BitcoinTestFramework (jnewbery) +- #12681 `1846296` Fix ComputeTimeSmart test failure with `-DDEBUG_LOCKORDER` (ryanofsky) +- #12682 `9f04c8e` travis: Clone depth 1 unless `$check_doc` (MarcoFalke) +- #12710 `00d1680` Append scripts to new `test_list` array to fix bad assignment (jeffrade) +- #12720 `872c921` Avoiding 'file' function name from python2 (jeffrade) +- #12728 `4ba3d4f` rename TestNode to TestP2PConn in tests (jnewbery) +- #12746 `2405ce1` Remove unused argument `max_invalid` from `check_estimates(…)` (practicalswift) +- #12718 `185d484` Require exact match in `assert_start_raises_init_eror` (jnewbery, MarcoFalke) +- #12076 `6d36f59` Use node.datadir instead of tmpdir in test framework (MarcoFalke) +- #12772 `b43aba8` ci: Bump travis timeout for make check to 50m (jnewbery) +- #12806 `18606eb` Fix function names in `feature_blocksdir` (MarcoFalke) +- #12811 `0d8fc8d` Make summary row bold-red if any test failed and show failed tests at end of table (laanwj) +- #12790 `490644d` Use blockmaxweight where tests previously had blockmaxsize (conscott) +- #11773 `f0f9732` Change `feature_block.py` to use BitcoinTestFramework (jnewbery) +- #12839 `40f4baf` Remove travis checkout depth (laanwj) +- #11817 `2a09a78` Change `feature_csv_activation.py` to use BitcoinTestFramework (jnewbery) +- #12284 `fa5825d` Remove assigned but never used local variables. Enable Travis checking for unused local variables (practicalswift) +- #12719 `9beded5` Add note about test suite naming convention in developer-notes.md (practicalswift) +- #12861 `c564424` Stop `feature_block.py` from blowing up memory (jnewbery) +- #12851 `648252e` travis: Run verify-commits only on cron jobs (MarcoFalke) +- #12853 `2106c4c` Match full plain text by default (MarcoFalke) +- #11818 `9a2db3b` I accidentally (deliberately) killed it (the ComparisonTestFramework) (jnewbery) +- #12766 `69310a3` Tidy up REST interface functional tests (romanz) +- #12849 `83c7533` Add logging in loops in `p2p_sendhears.py` (ccdle12) +- #12895 `d6f10b2` Add note about test suite name uniqueness requirement to developer notes (practicalswift) +- #12856 `27278df` Add Metaclass for BitcoinTestFramework (WillAyd) +- #12918 `6fc5a05` Assert on correct variable (kallewoof) +- #11878 `a04440f` Add Travis check for duplicate includes (practicalswift) +- #12917 `cf8073f` Windows fixups for functional tests (MarcoFalke) +- #12926 `dd1ca9e` Run unit tests in parallel (sipa) +- #12920 `b1fdfc1` Fix sign for expected values (kallewoof) +- #12947 `979f598` Wallet hd functional test speedup and clarification (instagibbs) +- #12993 `0d69921` Remove compatibility code not needed now when we're on Python 3 (practicalswift) +- #12996 `6a278e0` Remove redundant bytes(…) calls (practicalswift) +- #12949 `6b46288` Avoid copies of CTransaction (MarcoFalke) +- #13007 `0d12570` Fix dangling wallet pointer in vpwallets (promag) +- #13048 `cac6d11` Fix `feature_block` flakiness (jnewbery) +- #12510 `d5b2e98` Add `rpc_bind` test to default-run tests (laanwj) +- #13022 `896a9d0` Attach node index to `test_node` AssertionError and print messages (jamesob) +- #13024 `018c7e5` Add rpcauth pair that generated by rpcauth.py (ken2812221) +- #13013 `a0079d4` bench: Amend `mempool_eviction` test for witness txs (MarcoFalke) +- #13051 `e074097` Normalize executable location (MarcoFalke) +- #13056 `106d929` Make rpcauth.py testable and add unit tests (nixbox) +- #13073 `a785bc3` add rpcauth-test to `AC_CONFIG_LINKS` to fix out-of-tree make check (laanwj) +- #12830 `25ad2f7` Clarify address book error messages, add tests (jamesob) +- #13082 `24106a8` don't test against min relay fee information in `mining_prioritisetransaction.py` (kristapsk) +- #13003 `8d045a0` Add test for orphan handling (MarcoFalke) +- #13105 `9e9b48d` Add --failfast option to functional test runner (jamesob) +- #13130 `3186ad4` Fix race in `rpc_deprecated.py` (jnewbery) +- #13136 `baf6b4e` Fix flake8 warnings in several wallet functional tests (jnewbery) +- #13094 `bf9b03d` Add test for 64-bit Windows PE, modify 32-bit test results (ken2812221) +- #13183 `9458b05` travis: New travis job for `check_docs` steps (glaksmono) +- #12265 `1834d4d` fundrawtransaction: lock watch-only shared address (kallewoof) +- #13188 `4a50ec0` Remove unused option --srcdir (MarcoFalke) +- #12755 `612ba35` Better stderr testing (jnewbery) +- #13198 `196c5a9` Avoid printing to console during cache creation (sdaftuar) +- #13075 `cb9bbf7` Remove 'account' API from wallet functional tests (jnewbery) +- #13221 `ffa86af` travis: Rename the build stage `check_doc` to `lint` (practicalswift) +- #13205 `3cbd25f` Remove spurious error log in `p2p_segwit.py` (jnewbery) +- #13291 `536120e` Don't include torcontrol.cpp into the test file (Empact) +- #13281 `2ac6315` Move linters to test/lint, add readme (MarcoFalke) +- #13215 `f8a29ca` travis: Build tests on ubuntu 18.04 with docker (ken2812221) +- #13349 `24f7011` bench: Don't return a bool from main (laanwj) +- #13347 `87a9d03` travis: Skip cache for lint stage (MarcoFalke) +- #13355 `0b1c0c4` Fix "gmake check" under OpenBSD 6.3 (probably `*BSD`): Avoid using GNU grep specific regexp handling (practicalswift) +- #13353 `d4f6dac` Fixup setting of PATH env var (MarcoFalke) +- #13352 `e24bf1c` Avoid checking reject code for now (MarcoFalke) +- #13383 `2722a1f` bench: Use non-throwing parsedouble(…) instead of throwing boost::lexical_cast(…) (practicalswift) +- #13367 `264efdc` Increase includeconf test coverage (MarcoFalke) +- #13404 `3d3d8ae` speed up of `tx_validationcache_tests` by reusing of CTransaction (lucash-dev) +- #13421 `531a033` Remove `portseed_offset` from test runner (MarcoFalke) +- #13440 `5315660` Log as utf-8 (MarcoFalke) +- #13066 `fa4b906` Migrate verify-commits script to python, run in travis (ken2812221) +- #13447 `4b1edd3` travis: Increase `travis_wait` time while verifying commits (ken2812221) +- #13350 `f532d52` Add logging to provide anchor points when debugging p2p_sendheaders (lmanners) +- #13406 `4382f19` travis: Change mac goal to all deploy (ken2812221) +- #13457 `b222138` Drop variadic macro (MarcoFalke) +- #13512 `3a45493` mininode: Expose connection state through `is_connected` (MarcoFalke) +- #13496 `9ab4c2a` Harden lint-filenames.sh (wodry) +- #13219 `08516e0` bench: Add block assemble benchmark (MarcoFalke) +- #13530 `b1dc39d` bench: Add missing pow.h header (laanwj) +- #12686 `2643fa5` Add -ftrapv to CFLAGS and CXXFLAGS when --enable-debug is used. Enable -ftrapv in Travis (practicalswift) +- #12882 `d96bdd7` Make `test_bitcoin` pass under ThreadSanitzer (clang). Fix lock-order-inversion (potential deadlock) (practicalswift) +- #13535 `2328039` `wallet_basic`: Specify minimum required amount for listunspent (MarcoFalke) +- #13551 `c93c360` Fix incorrect documentation for test case `cuckoocache_hit_rate_ok` (practicalswift) +- #13563 `b330f3f` bench: Simplify coinselection (promag) +- #13517 `a6ed99a` Remove need to handle the network thread in tests (MarcoFalke) +- #13522 `686e97a` Fix `p2p_sendheaders` race (jnewbery) +- #13467 `3dc2dcf` Make `p2p_segwit` easier to debug (jnewbery) +- #13598 `0212187` bench: Fix incorrect behaviour in prevector.cpp (AkioNak) +- #13565 `b05ded1` Fix AreInputsStandard test to reference the proper scriptPubKey (Empact) +- #13145 `d3dae3d` Use common getPath method to create temp directory in tests (winder) +- #13645 `2ea7eb6` skip `rpc_zmq` functional test as necessary (jamesob) +- #13626 `8f1106d` Fix some TODOs in `p2p_segwit` (MarcoFalke) +- #13138 `8803c91` Remove accounts from `wallet_importprunedfunds.py` (jnewbery) +- #13663 `cbc9b50` Avoid read/write to default datadir (MarcoFalke) +- #13682 `f8a32a3` bench: Remove unused variable (practicalswift) +- #13638 `6fcdb5e` Use `MAX_SCRIPT_ELEMENT_SIZE` from script.py (domob1812) +- #13687 `9d26b69` travis: Check that ~/.bitcoin is never created (MarcoFalke) +- #13715 `e1260a7` fixes mininode's P2PConnection sending messages on closing transport (marcoagner) +- #13729 `aa9429a` travis: Avoid unnecessarily setting env variables on the lint build (Empact) +- #13747 `ab28b5b` Skip P2PConnection's `is_closing()` check when not available (domob1812) +- #13650 `7a9bca6` travis: Don't store debug info if --enable-debug is set (ken2812221) +- #13711 `f98d1e0` bench: Add benchmark for unserialize prevector (AkioNak) +- #13771 `365384f` travis: Retry to fetch docker image (MarcoFalke) +- #13806 `4d550ff` Fix `bench/block_assemble` assert failure (jamesob) +- #13779 `d25079a` travis: Improve readability of travis.yml and log outputs (scravy) +- #13822 `0fb9c87` bench: Make coinselection output groups pass eligibility filter (achow101) +- #13247 `e83d82a` Add tests to SingleThreadedSchedulerClient() and document the memory model (skeees) +- #13811 `660abc1` travis: Run `bench_bitcoin` once (MarcoFalke) +- #13837 `990e182` Extract `rpc_timewait` as test param (MarcoFalke) +- #13851 `9c4324d` fix locale for lint-shell (scravy) +- #13823 `489b51b` quote path in authproxy for external multiwallets (MarcoFalke) +- #13849 `2b67354` travis: Use only travis jobs: instead of mix of jobs+matrix (scravy) +- #13859 `2384323` Add emojis to `test_runner` path and wallet filename (MarcoFalke) +- #13916 `8ac7125` `wait_for_verack` by default (MarcoFalke) +- #13669 `f66e1c7` Cleanup `create_transaction` implementations (conscott) +- #13924 `09ada21` Simplify comparison in `rpc_blockchain.py` (domob1812) +- #13913 `a08533c` Remove redundant checkmempool/checkblockindex `extra_args` (MarcoFalke) +- #13915 `a04888a` Add test for max number of entries in locator (MarcoFalke) +- #13867 `1b04b55` Make extended tests pass on native Windows (MarcoFalke) +- #13944 `0df7a6c` Port usage of deprecated optparse module to argparse module (Kvaciral) +- #13928 `b8eb0df` blocktools enforce named args for amount (MarcoFalke) +- #13054 `bffb35f` Enable automatic detection of undefined names in Python tests scripts. Remove wildcard imports (practicalswift) +- #14069 `cf3d7f9` Use assert not `BOOST_CHECK_*` from multithreaded tests (skeees) +- #14071 `fab0fbe` Stop txindex thread before calling destructor (MarcoFalke) + +### Miscellaneous +- #11909 `8897135` contrib: Replace developer keys with list of pgp fingerprints (MarcoFalke) +- #12394 `fe53d5f` gitian-builder.sh: fix --setup doc, since lxc is default (Sjors) +- #12468 `294a766` Add missing newline in init.cpp log message (Aesti) +- #12308 `dcfe218` contrib: Add support for out-of-tree builds in gen-manpages.sh (laanwj) +- #12451 `aae64a2` Bump leveldb subtree (MarcoFalke) +- #12527 `d77b4a7` gitian-build.sh: fix signProg being recognized as two parameters (ken2812221) +- #12588 `d74b01d` utils: Remove deprecated pyzmq call from python zmq example (kosciej) +- #10271 `bc67982` Use `std::thread::hardware_concurrency`, instead of Boost, to determine available cores (fanquake) +- #12097 `14475e2` scripts: Lint-whitespace: use perl instead of grep -p (Sjors) +- #12098 `17c44b2` scripts: Lint-whitespace: add param to check last n commits (Sjors) +- #11900 `842f61a` script: Simplify checkminimalpush checks, add safety assert (instagibbs) +- #12567 `bb98aec` util: Print timestamp strings in logs using iso 8601 formatting (practicalswift) +- #12572 `d8d9162` script: Lint-whitespace: find errors more easily (AkioNak) +- #10694 `ae5bcc7` Remove redundant code in MutateTxSign(CMutableTransaction&, const std::string&) (practicalswift) +- #12659 `3d16f58` Improve Fatal LevelDB Log Messages (eklitzke) +- #12643 `0f0229d` util: Remove unused `sync_chain` (MarcoFalke) +- #12102 `7fb8fb4` Apply hardening measures in bitcoind systemd service file (Flowdalic) +- #12652 `55f490a` bitcoin-cli: Provide a better error message when bitcoind is not running (practicalswift) +- #12630 `c290508` Provide useful error message if datadir is not writable (murrayn) +- #11881 `624bee9` Remove Python2 support (jnewbery) +- #12821 `082e26c` contrib: Remove unused import string (MarcoFalke) +- #12829 `252c1b0` Python3 fixup (jnewbery) +- #12822 `ff48f62` Revert 7deba93bdc76616011a9f493cbc203d60084416f and fix expired-key-sigs properly (TheBlueMatt) +- #12820 `5e53b80` contrib: Fix check-doc script regexes (MarcoFalke) +- #12713 `4490871` Track negated options in the option parser (eklitzke) +- #12708 `b2e5fe8` Make verify-commits.sh test that merges are clean (sipa) +- #12891 `3190785` logging: Add lint-logs.sh to check for newline termination (jnewbery) +- #12923 `a7cbe38` util: Pass `pthread_self()` to `pthread_setschedparam` instead of 0 (laanwj) +- #12871 `fb17fae` Add shell script linting: Check for shellcheck warnings in shell scripts (practicalswift) +- #12970 `5df84de` logging: Bypass timestamp formatting when not logging (theuni) +- #12987 `fe8fa22` tests/tools: Enable additional Python flake8 rules for automatic linting via Travis (practicalswift) +- #12972 `0782508` Add python3 script shebang lint (ken2812221) +- #13004 `58bbc55` Print to console by default when not run with -daemon (practicalswift) +- #13039 `8b4081a` Add logging and error handling for file syncing (laanwj) +- #13020 `4741ca5` Consistently log CValidationState on call failure (Empact) +- #13031 `826acc9` Fix for utiltime to compile with msvc (sipsorcery) +- #13119 `81743b5` Remove script to clean up datadirs (MarcoFalke) +- #12954 `5a66642` util: Refactor logging code into a global object (jimpo) +- #12769 `35eb9d6` Add systemd service to bitcoind in debian package (ghost) +- #13146 `0bc980b` rpcauth: Make it possible to provide a custom password (laanwj) +- #13148 `b62b437` logging: Fix potential use-after-free in logprintstr(…) (practicalswift) +- #13214 `0612d96` Enable Travis checking for two Python linting rules we are currently not violating (practicalswift) +- #13197 `6826989` util: Warn about ignored recursive -includeconf calls (kallewoof) +- #13176 `d9ebb63` Improve CRollingBloomFilter performance: replace modulus with FastMod (martinus) +- #13228 `d792e47` Add script to detect circular dependencies between source modules (sipa) +- #13320 `e08c130` Ensure gitian-build.sh uses bash (jhfrontz) +- #13301 `e4082d5` lint: Add linter to error on `#include <*.cpp>` (Empact) +- #13374 `56f6936` utils and libraries: checking for bitcoin address in translations (kaplanmaxe) +- #13230 `7c32b41` Simplify include analysis by enforcing the developer guide's include syntax (practicalswift) +- #13450 `32bf4c6` Add linter: Enforce the source code file naming convention described in the developer notes (practicalswift) +- #13479 `fa2ea37` contrib: Fix cve-2018-12356 by hardening the regex (loganaden) +- #13448 `a90ca40` Add linter: Make sure we explicitly open all text files using UTF-8 encoding in Python (practicalswift) +- #13494 `d67eff8` Follow-up to #13454: Fix broken build by exporting `LC_ALL=C` (practicalswift) +- #13510 `03f3925` Scripts and tools: Obsolete #!/bin/bash shebang (DesWurstes) +- #13577 `c9eb8d1` logging: Avoid nstart may be used uninitialized in appinitmain warning (mruddy) +- #13603 `453ae5e` bitcoin-tx: Stricter check for valid integers (domob1812) +- #13118 `c05c93c` RPCAuth Detection in Logs (Linrono) +- #13647 `4027ec1` Scripts and tools: Fix `BIND_NOW` check in security-check.py (conradoplg) +- #13692 `f5d166a` contrib: Clone core repo in gitian-build (MarcoFalke) +- #13699 `4c6d1b9` contrib: Correct version check (kallewoof) +- #13695 `dcc0cff` lint: Add linter for circular dependencies (Empact) +- #13733 `0d1ebf4` utils: Refactor argsmanager a little (AtsukiTak) +- #13714 `29b4ee6` contrib: Add lxc network setup for bionic host (ken2812221) +- #13764 `f8685f4` contrib: Fix test-security-check fail in ubuntu 18.04 (ken2812221) +- #13809 `77168f7` contrib: Remove debian and rpm subfolder (MarcoFalke) +- #13799 `230652c` Ignore unknown config file options; warn instead of error (sipa) +- #13894 `df9f712` shutdown: Stop threads before resetting ptrs (MarcoFalke) +- #13925 `71dec5c` Merge leveldb subtree (MarcoFalke) +- #13939 `ef86f26` lint: Make format string linter understand basic template parameter syntax (practicalswift) +- #14105 `eb202ea` util: Report parse errors in configuration file (laanwj) +- #12604 `9903537` Add DynamicMemoryUsage() to CDBWrapper to estimate LevelDB memory use (eklitzke) +- #12495 `047865e` Increase LevelDB `max_open_files` (eklitzke) +- #12784 `e80716d` Fix bug in memory usage calculation (unintended integer division) (practicalswift) +- #12618 `becd8dd` Set `SCHED_BATCH` priority on the loadblk thread (eklitzke) +- #12854 `5ca1509` Add P2P, Network, and Qt categories to the desktop icon (luke-jr) +- #11862 `4366f61` Network specific conf sections (ajtowns) +- #13441 `4a7e64f` Prevent shared conf files from failing with different available options in different binaries (achow101) +- #13471 `5eca4e8` For AVX2 code, also check for AVX, XSAVE, and OS support (sipa) +- #13503 `c655b2c` Document FreeBSD quirk. Fix FreeBSD build: Use std::min(…) to allow for compilation under certain FreeBSD versions (practicalswift) +- #13725 `07ce278` Fix bitcoin-cli --version (Empact) + +### Documentation +- #12306 `216f9a4` Improvements to UNIX documentation (axvr) +- #12309 `895fbd7` Explain how to update chainTxData in release process (laanwj) +- #12317 `85123be` Document method for reviewers to verify chainTxData (jnewbery) +- #12331 `d32528e` Properly alphabetize output of CLI --help option (murrayn) +- #12322 `c345148` Remove step making cloned repository world-writable for Windows build (murrayn) +- #12354 `b264528` add gpg key for fivepiece (fivepiece) +- #11761 `89005dd` initial QT documentation (Sjors) +- #12232 `fdc2188` Improve "Turn Windows Features On or Off" step (MCFX2) +- #12487 `4528f74` init: Remove translation for `-blockmaxsize` option help (laanwj) +- #12546 `a4a5fc7` Minor improvements to Compatibility Notes (randolf) +- #12434 `21e2670` dev-notes: Members should be initialized (MarcoFalke) +- #12452 `71f56da` clarified systemd installation instructions in init.md for Ubuntu users (DaveFromBinary) +- #12615 `1f93491` allow for SIGNER containing spaces (ken2812221) +- #12603 `85424d7` PeerLogicValidation interface (jamesob) +- #12581 `12ac2f0` Mention configure without wallet in FreeBSD instructions (dbolser) +- #12619 `8a709fb` Give hint about gitian not able to download (kallewoof) +- #12668 `de2fcaa` do update before fetching packages in WSL build guide (nvercamm) +- #12586 `e7721e6` Update osx brew install instruction (fanquake) +- #12760 `7466a26` Improve documentation on standard communication channels (jimpo) +- #12797 `0415b1e` init: Fix help message for checkblockindex (MarcoFalke) +- #12800 `2d97611` Add note about our preference for scoped enumerations ("enum class") (practicalswift) +- #12798 `174d016` Refer to witness reserved value as spec. in the BIP (MarcoFalke) +- #12759 `d3908e2` Improve formatting of developer notes (eklitzke) +- #12877 `2b54155` Use bitcoind in Tor documentation (knoxcard) +- #12896 `b15485e` Fix conflicting statements about initialization in developer notes (practicalswift) +- #12850 `319991d` add qrencode to brew install instructions (buddilla) +- #12007 `cd8e45b` Clarify the meaning of fee delta not being a fee rate in prioritisetransaction RPC (honzik666) +- #12927 `06ead15` fixed link, replaced QT with Qt (trulex) +- #12852 `ebd786b` devtools: Setup ots git integration (MarcoFalke) +- #12933 `3cf76c2` Refine header include policy (MarcoFalke) +- #12951 `6df0c6c` Fix comment in FindForkInGlobalIndex (jamesob) +- #12982 `a63b4e3` Fix inconsistent namespace formatting guidelines (ryanofsky) +- #13026 `9b3a67e` Fix include comment in src/interfaces/wallet.h (promag) +- #13012 `d1e3c5e` Add comments for chainparams.h, validation.cpp (jamesob) +- #13064 `569e381` List support for BIP173 in bips.md (sipa) +- #12997 `646b7f6` build-windows: Switch to Artful, since Zesty is EOL (MarcoFalke) +- #12384 `c5f7efe` Add version footnote to tor.md (Willtech) +- #13165 `627c376` Mention good first issue list in CONTRIBUTING.md (fanquake) +- #13295 `fb77310` Update OpenBSD build instructions for OpenBSD 6.3 (practicalswift) +- #13340 `3a8e3f4` remove leftover check-doc documentation (fanquake) +- #13346 `60f0358` update bitcoin-dot-org links in release-process.md (fanquake) +- #13372 `f014933` split FreeBSD build instructions out of build-unix.md (steverusso) +- #13366 `861de3b` Rename “OS X” to the newer “macOS” convention (giulio92) +- #13369 `f8bcef3` update transifex doc link (mess110) +- #13312 `b22115d` Add a note about the source code filename naming convention (practicalswift) +- #13460 `1939536` Remove note to install all boost dev packages (MarcoFalke) +- #13476 `9501938` Fix incorrect shell quoting in FreeBSD build instructions (murrayn) +- #13402 `43fa355` Document validationinterace callback blocking deadlock potential (TheBlueMatt) +- #13488 `d6cf4bd` Improve readability of "Squashing commits" (wodry) +- #13531 `ee02deb` Clarify that mempool txiter is `const_iterator` (MarcoFalke) +- #13418 `01f9098` More precise explanation of parameter onlynet (wodry) +- #13592 `1756cb4` Modify policy to not translate command-line help (ken2812221) +- #13588 `b77c38e` Improve doc of options addnode, connect, seednode (wodry) +- #13614 `17e9106` Update command line help for -printtoconsole and -debuglogfile (satwo, fanquake) +- #13605 `8cc048e` corrected text to reflect new(er) process of specifying fingerprints (jhfrontz) +- #13481 `b641f60` Rewrite some validation docs as lock annotations (MarcoFalke) +- #13680 `30640f8` Remove outdated comment about miner ignoring CPFP (jamesob) +- #13625 `7146672` Add release notes for -printtoconsole and -debuglogfile changes (satwo) +- #13718 `f7f574d` Specify preferred Python string formatting technique (masonicboom) +- #12764 `10b9a81` Remove field in getblocktemplate help that has never been used (conscott) +- #13742 `d2186b3` Adjust bitcoincore.org links (MarcoFalke) +- #13706 `94dd89e` Minor improvements to release-process.md (MitchellCash) +- #13775 `ef4fac0` Remove newlines from error message (practicalswift) +- #13803 `feb7dd9` add note to contributor docs about warranted PR's (kallewoof) +- #13814 `67af7ef` Add BIP174 to list of implemented BIPs (sipa) +- #13835 `c1cba35` Fix memory consistency model in comment (skeees) +- #13824 `aa30e4b` Remove outdated net comment (MarcoFalke) +- #13853 `317477a` correct versions in dependencies.md (fanquake) +- #13872 `37ab117` Reformat -help output for help2man (real-or-random) +- #13717 `8c3c402` Link to python style guidelines from developer notes (masonicboom) +- #13895 `1cd5f2c` fix GetWarnings docs to reflect behavior (Empact) +- #13911 `3e3a50a` Revert translated string change, clarify wallet log messages (PierreRochard) +- #13908 `d6faea4` upgrade rescan time warning from minutes to >1 hour (masonicboom) +- #13905 `73a09b4` fixed bitcoin-cli -help output for help2man (hebasto) +- #14100 `2936dbc` Change documentation for =0 for non-boolean options (laanwj) +- #14096 `465a583` Add reference documentation for descriptors language (sipa) +- #12757 `0c5f67b` Clarify include guard naming convention (practicalswift) +- #13844 `d3325b0` Correct the help output for `-prune` (hebasto) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- 251 +- 532479301 +- Aaron Clauson +- Akio Nakamura +- Akira Takizawa +- Alex Morcos +- Alex Vear +- Alexey Ivanov +- Alin Rus +- Andrea Comand +- Andrew Chow +- Anthony Towns +- AtsukiTak +- Ben Woosley +- Bernhard M. Wiedemann +- Brandon Ruggles +- buddilla +- ccdle12 +- Chris Moore +- Chun Kuan Lee +- Clem Taylor +- Conor Scott +- Conrado Gouvea +- Cory Fields +- Cristian Mircea Messel +- ctp-tsteenholdt +- Damian Williamson +- Dan Bolser +- Daniel Kraft +- Darko Janković +- DaveFromBinary +- David A. Harding +- DesWurstes +- Dimitris Apostolou +- donaloconnor +- Douglas Roark +- DrahtBot +- Drew Rasmussen +- e0 +- Ernest Hemingway +- Ethan Heilman +- Evan Klitzke +- fanquake +- Felix Wolfsteller +- fivepiece +- Florian Schmaus +- Fuzzbawls +- Gabriel Davidian +- Giulio Lombardo +- Gleb +- Grady Laksmono +- GreatSock +- Gregory Maxwell +- Gregory Sanders +- Hennadii Stepanov +- Henrik Jonsson +- Indospace.io +- James O'Beirne +- Jan Čapek +- Jeff Frontz +- Jeff Rade +- Jeremy Rubin +- JeremyRand +- Jesse Cohen +- Jim Posen +- joemphilips +- John Bampton +- John Newbery +- johnlow95 +- Johnson Lau +- Jonas Nick +- Jonas Schnelli +- João Barbosa +- Jorge Timón +- Josh Hartshorn +- Julian Fleischer +- kallewoof +- Karel Bilek +- Karl-Johan Alm +- Ken Lee +- Kevin Pan +- Kosta Zertsekel +- Kristaps Kaupe +- Kvaciral +- Lawrence Nahum +- Linrono +- lmanners +- Loganaden Velvindron +- Lowell Manners +- lucash.dev@gmail.com +- Luke Dashjr +- lutangar +- Marcin Jachymiak +- marcoagner +- MarcoFalke +- Mark Erhardt +- Mark Friedenbach +- Martin Ankerl +- Mason Simon +- Matt Corallo +- Matteo Sumberaz +- Max Kaplan +- MeshCollider +- Michał Zabielski +- Mitchell Cash +- mruddy +- mryandao +- murrayn +- Nick Vercammen +- Nicolas Dorier +- Nikolay Mitev +- okayplanet +- Pierre Rochard +- Pieter Wuille +- practicalswift +- Qasim Javed +- Randolf Richardson +- Richard Kiss +- Roman Zeyde +- Russell Yanofsky +- Samuel B. Atwood +- Sebastian Kung +- Sjors Provoost +- Steve Lee +- steverusso +- Suhas Daftuar +- Tamas Blummer +- TheCharlatan +- Thomas Kerin +- Thomas Snider +- Tim Ruffing +- Varunram +- Vasil Dimov +- Will Ayd +- William Robinson +- winder +- Wladimir J. van der Laan +- wodry + +And to those that reported security issues: + +- awemany (for CVE-2018-17144, previously credited as "anonymous reporter") + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). \ No newline at end of file From ff94da78874550e3ae472686fdb6dd78a457eafd Mon Sep 17 00:00:00 2001 From: practicalswift Date: Wed, 3 Oct 2018 11:36:54 +0200 Subject: [PATCH 082/263] tests: Make appveyor run with --usecli --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index d7ce2224e9..57319d24f6 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -46,7 +46,7 @@ after_build: before_test: - ps: ${conf_ini} = (Get-Content([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini.in"))) - ps: ${conf_ini} = $conf_ini.Replace("@abs_top_srcdir@", ${env:APPVEYOR_BUILD_FOLDER}).Replace("@abs_top_builddir@", ${env:APPVEYOR_BUILD_FOLDER}).Replace("@EXEEXT@", ".exe") -- ps: ${conf_ini} = $conf_ini.Replace("@ENABLE_WALLET_TRUE@", "").Replace("@BUILD_BITCOIN_UTILS_TRUE@", "").Replace("@BUILD_BITCOIND_TRUE@", "").Replace("@ENABLE_ZMQ_TRUE@", "") +- ps: ${conf_ini} = $conf_ini.Replace("@ENABLE_WALLET_TRUE@", "").Replace("@BUILD_BITCOIN_CLI_TRUE@", "").Replace("@BUILD_BITCOIND_TRUE@", "").Replace("@ENABLE_ZMQ_TRUE@", "") - ps: ${utf8} = New-Object System.Text.UTF8Encoding ${false} - ps: '[IO.File]::WriteAllLines([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini"), $conf_ini, ${utf8})' - ps: move "build_msvc\${env:PLATFORM}\${env:CONFIGURATION}\*.exe" src From 1f59c6f3eb6c2d5b8dcff04dc3334ee0f0de5b17 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 3 Oct 2018 12:46:14 +0200 Subject: [PATCH 083/263] doc: Remove "temporary file" notice from 0.17.0 release notes not that temporary anymore Tree-SHA512: c44bfca71573b3d70001d339138715fc6fbceae2e370f2e1e8ba5bdfdb19e8ec4b0a59d45ff8565e0f784d4659f51e8089a6d892a73362b428d8a98097fc8532 --- doc/release-notes/release-notes-0.17.0.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/release-notes/release-notes-0.17.0.md b/doc/release-notes/release-notes-0.17.0.md index 1b6e2f8e6c..ce7a1f6ac1 100644 --- a/doc/release-notes/release-notes-0.17.0.md +++ b/doc/release-notes/release-notes-0.17.0.md @@ -1,6 +1,3 @@ -(note: this is a temporary file, to be added-to by anybody, and moved to -release-notes at release time) - Bitcoin Core version 0.17.0 is now available from: @@ -1105,4 +1102,4 @@ And to those that reported security issues: - awemany (for CVE-2018-17144, previously credited as "anonymous reporter") -As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). \ No newline at end of file +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From f149e31ea2f28b72dbc3e7d7a8fe31466eabef85 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 3 Oct 2018 16:49:51 -0400 Subject: [PATCH 084/263] depends: qt: avoid system harfbuzz and bz2 We may eventually want to break out harfbuzz and build it in depends, but for now just ensure that runtime dependencies don't depend on whether or not harfbuzz was present on the builder. --- depends/packages/freetype.mk | 2 +- depends/packages/qt.mk | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index 76b025c463..41e02e2030 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -5,7 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88 define $(package)_set_vars - $(package)_config_opts=--without-zlib --without-png --disable-static + $(package)_config_opts=--without-zlib --without-png --without-harfbuzz --without-bzip2 --disable-static $(package)_config_opts_linux=--with-pic endef diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index d15f147cd7..dc1d17cd57 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -64,6 +64,7 @@ $(package)_config_opts += -prefix $(host_prefix) $(package)_config_opts += -qt-libpng $(package)_config_opts += -qt-libjpeg $(package)_config_opts += -qt-pcre +$(package)_config_opts += -qt-harfbuzz $(package)_config_opts += -system-zlib $(package)_config_opts += -static $(package)_config_opts += -silent From d10f2cd7d8506aec8b406c346b35d3c31f0f37df Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 3 Oct 2018 18:59:03 -0300 Subject: [PATCH 085/263] travis: set codespell version to avoid breakage --- .travis/lint_04_install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis/lint_04_install.sh b/.travis/lint_04_install.sh index 3a6ff73d79..7925189021 100755 --- a/.travis/lint_04_install.sh +++ b/.travis/lint_04_install.sh @@ -6,5 +6,5 @@ export LC_ALL=C -travis_retry pip install codespell +travis_retry pip install codespell==1.13.0 travis_retry pip install flake8 From 3b706212ad319423147c9ccc681556c052050186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20B=C3=ADlek?= Date: Thu, 4 Oct 2018 15:46:22 +0900 Subject: [PATCH 086/263] doc: RPC documentation --- doc/release-process.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release-process.md b/doc/release-process.md index 3ba622ee6d..f2fe44c8bf 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -296,6 +296,8 @@ bitcoin.org (see below for bitcoin.org update instructions). - bitcoincore.org blog post + - bitcoincore.org RPC documentation update + - Update title of #bitcoin on Freenode IRC - Optionally twitter, reddit /r/Bitcoin, ... but this will usually sort out itself From 86eddd466e33769c0699c08b978cb7d87c660229 Mon Sep 17 00:00:00 2001 From: poiuty Date: Thu, 4 Oct 2018 18:49:05 +0300 Subject: [PATCH 087/263] doc: miss install --- doc/build-unix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/build-unix.md b/doc/build-unix.md index 9162098967..87dade42a3 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -74,7 +74,7 @@ Build requirements: Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: - sudo apt-get libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev + sudo apt-get install libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev BerkeleyDB is required for the wallet. From 4a9f064ea10e58220dce114e0fafa90ff8f1fcdf Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Thu, 4 Oct 2018 21:58:24 +0300 Subject: [PATCH 088/263] Fix typos --- doc/build-windows.md | 2 +- doc/developer-notes.md | 4 ++-- doc/init.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/build-windows.md b/doc/build-windows.md index 12adadacdc..8c4b79bebc 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -133,7 +133,7 @@ Installation ------------- After building using the Windows subsystem it can be useful to copy the compiled -executables to a directory on the windows drive in the same directory structure +executables to a directory on the Windows drive in the same directory structure as they appear in the release `.zip` archive. This can be done in the following way. This will install to `c:\workspace\bitcoin`, for example: diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 1d103d481b..c86648c5b8 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -705,10 +705,10 @@ Current subtrees include: - Upstream at https://github.com/google/leveldb ; Maintained by Google, but open important PRs to Core to avoid delay. - **Note**: Follow the instructions in [Upgrading LevelDB](#upgrading-leveldb) when - merging upstream changes to the leveldb subtree. + merging upstream changes to the LevelDB subtree. - src/libsecp256k1 - - Upstream at https://github.com/bitcoin-core/secp256k1/ ; actively maintaned by Core contributors. + - Upstream at https://github.com/bitcoin-core/secp256k1/ ; actively maintained by Core contributors. - src/crypto/ctaes - Upstream at https://github.com/bitcoin-core/ctaes ; actively maintained by Core contributors. diff --git a/doc/init.md b/doc/init.md index 239b74e4e1..5778b09d05 100644 --- a/doc/init.md +++ b/doc/init.md @@ -22,7 +22,7 @@ Configuration At a bare minimum, bitcoind requires that the rpcpassword setting be set when running as a daemon. If the configuration file does not exist or this -setting is not set, bitcoind will shutdown promptly after startup. +setting is not set, bitcoind will shut down promptly after startup. This password does not have to be remembered or typed as it is mostly used as a fixed token that bitcoind and client programs read from the configuration From 59a50c217968e9b11d9175b4c156824e596aebc2 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Mon, 17 Sep 2018 21:36:21 +0800 Subject: [PATCH 089/263] appveyor: trivial build cache modifications --- .appveyor.yml | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 57319d24f6..ff84c01a39 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,12 +6,11 @@ platform: x64 environment: APPVEYOR_SAVE_CACHE_ON_ERROR: true CLCACHE_SERVER: 1 - PACKAGES: boost-filesystem boost-signals2 boost-interprocess boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb + PACKAGES: boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb PYTHONIOENCODING: utf-8 cache: - C:\tools\vcpkg\installed - C:\Users\appveyor\clcache -- build_msvc\cache init: - cmd: set PATH=C:\Python36-x64;C:\Python36-x64\Scripts;%PATH% install: @@ -23,32 +22,39 @@ install: $env:ALL_PACKAGES += $packages[$i] + ":" + $env:PLATFORM + "-windows-static " } - cmd: git -C C:\Tools\vcpkg pull # This is a temporary fix, can be removed after appveyor update its image to include Microsoft/vcpkg#4046 +- cmd: C:\Tools\vcpkg\bootstrap-vcpkg.bat +- cmd: vcpkg remove --recurse --outdated - cmd: vcpkg install %ALL_PACKAGES% -- cmd: vcpkg upgrade --no-dry-run - cmd: del /s /q C:\Tools\vcpkg\installed\%PLATFORM%-windows-static\debug # Remove unused debug library before_build: -- cmd: if not exist build_msvc\cache\ (del build_msvc\cache & mkdir build_msvc\cache) -- cmd: if not exist build_msvc\%PLATFORM%\%CONFIGURATION%\ (mkdir build_msvc\%PLATFORM%\%CONFIGURATION%) -- cmd: if exist build_msvc\cache\*.iobj (move build_msvc\cache\* build_msvc\%PLATFORM%\%CONFIGURATION%\) -- cmd: clcache -M 2147483648 +- ps: clcache -M 536870912 - cmd: python build_msvc\msvc-autogen.py - ps: $files = (Get-ChildItem -Recurse | where {$_.extension -eq ".vcxproj"}).FullName -- ps: for ($i = 0; $i -lt $files.length; $i++) { - (Get-Content $files[$i]).Replace("", "None").Replace("NDEBUG;", "") | Set-Content $files[$i] +- ps: for (${i} = 0; ${i} -lt ${files}.length; ${i}++) { + ${content} = (Get-Content ${files}[${i}]); + ${content} = ${content}.Replace("", "None"); + ${content} = ${content}.Replace("true", "false"); + ${content} = ${content}.Replace("NDEBUG;", ""); + Set-Content ${files}[${i}] ${content}; } - ps: Start-Process clcache-server +- ps: fsutil behavior set disablelastaccess 0 # Enable Access time feature on Windows (for clcache) build_script: - cmd: msbuild /p:TrackFileAccess=false /p:CLToolExe=clcache.exe build_msvc\bitcoin.sln /m /v:q /nowarn:C4244;C4267;C4715 /nologo after_build: -- cmd: move build_msvc\%PLATFORM%\%CONFIGURATION%\*.iobj build_msvc\cache\ -- cmd: move build_msvc\%PLATFORM%\%CONFIGURATION%\*.ipdb build_msvc\cache\ -- cmd: del C:\Users\appveyor\clcache\stats.txt +- ps: fsutil behavior set disablelastaccess 0 # Disable Access time feature on Windows (better performance) +- ps: clcache -z before_test: - ps: ${conf_ini} = (Get-Content([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini.in"))) -- ps: ${conf_ini} = $conf_ini.Replace("@abs_top_srcdir@", ${env:APPVEYOR_BUILD_FOLDER}).Replace("@abs_top_builddir@", ${env:APPVEYOR_BUILD_FOLDER}).Replace("@EXEEXT@", ".exe") -- ps: ${conf_ini} = $conf_ini.Replace("@ENABLE_WALLET_TRUE@", "").Replace("@BUILD_BITCOIN_CLI_TRUE@", "").Replace("@BUILD_BITCOIND_TRUE@", "").Replace("@ENABLE_ZMQ_TRUE@", "") +- ps: ${conf_ini} = ${conf_ini}.Replace("@abs_top_srcdir@", ${env:APPVEYOR_BUILD_FOLDER}) +- ps: ${conf_ini} = ${conf_ini}.Replace("@abs_top_builddir@", ${env:APPVEYOR_BUILD_FOLDER}) +- ps: ${conf_ini} = ${conf_ini}.Replace("@EXEEXT@", ".exe") +- ps: ${conf_ini} = ${conf_ini}.Replace("@ENABLE_WALLET_TRUE@", "") +- ps: ${conf_ini} = ${conf_ini}.Replace("@BUILD_BITCOIN_CLI_TRUE@", "") +- ps: ${conf_ini} = ${conf_ini}.Replace("@BUILD_BITCOIND_TRUE@", "") +- ps: ${conf_ini} = ${conf_ini}.Replace("@ENABLE_ZMQ_TRUE@", "") - ps: ${utf8} = New-Object System.Text.UTF8Encoding ${false} -- ps: '[IO.File]::WriteAllLines([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini"), $conf_ini, ${utf8})' +- ps: '[IO.File]::WriteAllLines([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini"), ${conf_ini}, ${utf8})' - ps: move "build_msvc\${env:PLATFORM}\${env:CONFIGURATION}\*.exe" src test_script: - cmd: src\test_bitcoin.exe From b09c81454eb2fc7fb8d29301ce7f4aa3aaee35a5 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Fri, 5 Oct 2018 16:43:09 +0900 Subject: [PATCH 090/263] Don't access out of bounds array entry array[sizeof(array)] --- src/bench/checkblock.cpp | 4 ++-- src/test/script_tests.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index 6f03581c4b..e325333c01 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -20,7 +20,7 @@ namespace block_bench { static void DeserializeBlockTest(benchmark::State& state) { CDataStream stream((const char*)block_bench::block413567, - (const char*)&block_bench::block413567[sizeof(block_bench::block413567)], + (const char*)block_bench::block413567 + sizeof(block_bench::block413567), SER_NETWORK, PROTOCOL_VERSION); char a = '\0'; stream.write(&a, 1); // Prevent compaction @@ -36,7 +36,7 @@ static void DeserializeBlockTest(benchmark::State& state) static void DeserializeAndCheckBlockTest(benchmark::State& state) { CDataStream stream((const char*)block_bench::block413567, - (const char*)&block_bench::block413567[sizeof(block_bench::block413567)], + (const char*)block_bench::block413567 + sizeof(block_bench::block413567), SER_NETWORK, PROTOCOL_VERSION); char a = '\0'; stream.write(&a, 1); // Prevent compaction diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 67c377778f..7fbf37e7fb 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1013,21 +1013,21 @@ BOOST_AUTO_TEST_CASE(script_PushData) ScriptError err; std::vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); + BOOST_CHECK(EvalScript(directStack, CScript(direct, direct + sizeof(direct)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(pushdata1, pushdata1 + sizeof(pushdata1)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(pushdata2, pushdata2 + sizeof(pushdata2)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(pushdata4, pushdata4 + sizeof(pushdata4)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } From a6b5ec18ff39ef3ccd19ec0e6db9ae00602d8938 Mon Sep 17 00:00:00 2001 From: marcoagner Date: Fri, 5 Oct 2018 13:33:21 +0100 Subject: [PATCH 091/263] rpc: creates possibility to preserve labels on importprivkey - changes importprivkey behavior to overwrite existent label if one is passed and keep existing ones if no label is passed - tests behavior of importprivkey on existing address labels and different same key destination --- doc/release-notes-pr13381.md | 29 +++++ src/wallet/rpcdump.cpp | 11 +- test/functional/test_runner.py | 1 + test/functional/wallet_import_with_label.py | 134 ++++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 doc/release-notes-pr13381.md create mode 100755 test/functional/wallet_import_with_label.py diff --git a/doc/release-notes-pr13381.md b/doc/release-notes-pr13381.md new file mode 100644 index 0000000000..75faad9906 --- /dev/null +++ b/doc/release-notes-pr13381.md @@ -0,0 +1,29 @@ +RPC importprivkey: new label behavior +------------------------------------- + +Previously, `importprivkey` automatically added the default empty label +("") to all addresses associated with the imported private key. Now it +defaults to using any existing label for those addresses. For example: + +- Old behavior: you import a watch-only address with the label "cold + wallet". Later, you import the corresponding private key using the + default settings. The address's label is changed from "cold wallet" + to "". + +- New behavior: you import a watch-only address with the label "cold + wallet". Later, you import the corresponding private key using the + default settings. The address's label remains "cold wallet". + +In both the previous and current case, if you directly specify a label +during the import, that label will override whatever previous label the +addresses may have had. Also in both cases, if none of the addresses +previously had a label, they will still receive the default empty label +(""). Examples: + +- You import a watch-only address with the label "temporary". Later you + import the corresponding private key with the label "final". The + address's label will be changed to "final". + +- You use the default settings to import a private key for an address that + was not previously in the wallet. Its addresses will receive the default + empty label (""). diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index c97bc38e6f..701da0cf84 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -113,7 +113,7 @@ UniValue importprivkey(const JSONRPCRequest& request) "Hint: use importmulti to import more than one private key.\n" "\nArguments:\n" "1. \"privkey\" (string, required) The private key (see dumpprivkey)\n" - "2. \"label\" (string, optional, default=\"\") An optional label\n" + "2. \"label\" (string, optional, default=current label if address exists, otherwise \"\") An optional label\n" "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n" "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n" @@ -162,9 +162,14 @@ UniValue importprivkey(const JSONRPCRequest& request) CKeyID vchAddress = pubkey.GetID(); { pwallet->MarkDirty(); - // We don't know which corresponding address will be used; label them all + + // We don't know which corresponding address will be used; + // label all new addresses, and label existing addresses if a + // label was passed. for (const auto& dest : GetAllDestinationsForKey(pubkey)) { - pwallet->SetAddressBook(dest, strLabel, "receive"); + if (!request.params[1].isNull() || pwallet->mapAddressBook.count(dest) == 0) { + pwallet->SetAddressBook(dest, strLabel, "receive"); + } } // Don't throw error in case a key is already there diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index d9960460d9..de3b6e400c 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -157,6 +157,7 @@ 'feature_nulldummy.py', 'mempool_accept.py', 'wallet_import_rescan.py', + 'wallet_import_with_label.py', 'rpc_bind.py --ipv4', 'rpc_bind.py --ipv6', 'rpc_bind.py --nonloopback', diff --git a/test/functional/wallet_import_with_label.py b/test/functional/wallet_import_with_label.py new file mode 100755 index 0000000000..95acaa752e --- /dev/null +++ b/test/functional/wallet_import_with_label.py @@ -0,0 +1,134 @@ +#!/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 the behavior of RPC importprivkey on set and unset labels of +addresses. + +It tests different cases in which an address is imported with importaddress +with or without a label and then its private key is imported with importprivkey +with and without a label. +""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + + +class ImportWithLabel(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 2 + self.setup_clean_chain = True + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + """Main test logic""" + + self.log.info( + "Test importaddress with label and importprivkey without label." + ) + self.log.info("Import a watch-only address with a label.") + address = self.nodes[0].getnewaddress() + label = "Test Label" + self.nodes[1].importaddress(address, label) + address_assert = self.nodes[1].getaddressinfo(address) + + assert_equal(address_assert["iswatchonly"], True) + assert_equal(address_assert["ismine"], False) + assert_equal(address_assert["label"], label) + + self.log.info( + "Import the watch-only address's private key without a " + "label and the address should keep its label." + ) + priv_key = self.nodes[0].dumpprivkey(address) + self.nodes[1].importprivkey(priv_key) + + assert_equal(label, self.nodes[1].getaddressinfo(address)["label"]) + + self.log.info( + "Test importaddress without label and importprivkey with label." + ) + self.log.info("Import a watch-only address without a label.") + address2 = self.nodes[0].getnewaddress() + self.nodes[1].importaddress(address2) + address_assert2 = self.nodes[1].getaddressinfo(address2) + + assert_equal(address_assert2["iswatchonly"], True) + assert_equal(address_assert2["ismine"], False) + assert_equal(address_assert2["label"], "") + + self.log.info( + "Import the watch-only address's private key with a " + "label and the address should have its label updated." + ) + priv_key2 = self.nodes[0].dumpprivkey(address2) + label2 = "Test Label 2" + self.nodes[1].importprivkey(priv_key2, label2) + + assert_equal(label2, self.nodes[1].getaddressinfo(address2)["label"]) + + self.log.info("Test importaddress with label and importprivkey with label.") + self.log.info("Import a watch-only address with a label.") + address3 = self.nodes[0].getnewaddress() + label3_addr = "Test Label 3 for importaddress" + self.nodes[1].importaddress(address3, label3_addr) + address_assert3 = self.nodes[1].getaddressinfo(address3) + + assert_equal(address_assert3["iswatchonly"], True) + assert_equal(address_assert3["ismine"], False) + assert_equal(address_assert3["label"], label3_addr) + + self.log.info( + "Import the watch-only address's private key with a " + "label and the address should have its label updated." + ) + priv_key3 = self.nodes[0].dumpprivkey(address3) + label3_priv = "Test Label 3 for importprivkey" + self.nodes[1].importprivkey(priv_key3, label3_priv) + + assert_equal(label3_priv, self.nodes[1].getaddressinfo(address3)["label"]) + + self.log.info( + "Test importprivkey won't label new dests with the same " + "label as others labeled dests for the same key." + ) + self.log.info("Import a watch-only legacy address with a label.") + address4 = self.nodes[0].getnewaddress() + label4_addr = "Test Label 4 for importaddress" + self.nodes[1].importaddress(address4, label4_addr) + address_assert4 = self.nodes[1].getaddressinfo(address4) + + assert_equal(address_assert4["iswatchonly"], True) + assert_equal(address_assert4["ismine"], False) + assert_equal(address_assert4["label"], label4_addr) + + self.log.info("Asserts address has no embedded field with dests.") + + assert_equal(address_assert4.get("embedded"), None) + + self.log.info( + "Import the watch-only address's private key without a " + "label and new destinations for the key should have an " + "empty label while the 'old' destination should keep " + "its label." + ) + priv_key4 = self.nodes[0].dumpprivkey(address4) + self.nodes[1].importprivkey(priv_key4) + address_assert4 = self.nodes[1].getaddressinfo(address4) + + assert address_assert4.get("embedded") + + bcaddress_assert = self.nodes[1].getaddressinfo( + address_assert4["embedded"]["address"] + ) + + assert_equal(address_assert4["label"], label4_addr) + assert_equal(bcaddress_assert["label"], "") + + self.stop_nodes() + + +if __name__ == "__main__": + ImportWithLabel().main() From 3045704502e8a241b60b847fd52fcbed3129a2e4 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 2 Oct 2018 23:12:17 +0300 Subject: [PATCH 092/263] Add "Blocksdir" to Debug window To get the current blocksdir is valuable for debug purposes after merging #12653. --- src/qt/clientmodel.cpp | 5 +++ src/qt/clientmodel.h | 1 + src/qt/forms/debugwindow.ui | 62 ++++++++++++++++++++++++++----------- src/qt/rpcconsole.cpp | 1 + 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index b2cf4b6399..183444efab 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -177,6 +177,11 @@ QString ClientModel::dataDir() const return GUIUtil::boostPathToQString(GetDataDir()); } +QString ClientModel::blocksDir() const +{ + return GUIUtil::boostPathToQString(GetBlocksDir()); +} + void ClientModel::updateBanlist() { banTableModel->refresh(); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index ed7ecbf73b..79e7074cca 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -69,6 +69,7 @@ class ClientModel : public QObject bool isReleaseVersion() const; QString formatClientStartupTime() const; QString dataDir() const; + QString blocksDir() const; bool getProxyInfo(std::string& ip_port) const; diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 695ed61228..322a84ee92 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -142,13 +142,39 @@ + + + Blocksdir + + + + + + + IBeamCursor + + + N/A + + + Qt::PlainText + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + Startup time - + IBeamCursor @@ -164,7 +190,7 @@ - + @@ -177,14 +203,14 @@ - + Name - + IBeamCursor @@ -200,14 +226,14 @@ - + Number of connections - + IBeamCursor @@ -223,7 +249,7 @@ - + @@ -236,14 +262,14 @@ - + Current number of blocks - + IBeamCursor @@ -259,14 +285,14 @@ - + Last block time - + IBeamCursor @@ -282,7 +308,7 @@ - + @@ -295,14 +321,14 @@ - + Current number of transactions - + IBeamCursor @@ -318,14 +344,14 @@ - + Memory usage - + IBeamCursor @@ -341,7 +367,7 @@ - + 3 @@ -381,7 +407,7 @@ - + Qt::Vertical diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 3857befdf2..5bf9893141 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -661,6 +661,7 @@ void RPCConsole::setClientModel(ClientModel *model) ui->clientVersion->setText(model->formatFullVersion()); ui->clientUserAgent->setText(model->formatSubVersion()); ui->dataDir->setText(model->dataDir()); + ui->blocksDir->setText(model->blocksDir()); ui->startupTime->setText(model->formatClientStartupTime()); ui->networkName->setText(QString::fromStdString(Params().NetworkIDString())); From 36323e2ac6cca134de47b06c3f6403de91ee9eda Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 3 Oct 2018 19:06:12 +0300 Subject: [PATCH 093/263] Clean systray icon menu for -disablewallet mode Ref #3392 --- src/qt/bitcoingui.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 51aff08c42..311841017f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -620,14 +620,16 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu->addAction(toggleHideAction); trayIconMenu->addSeparator(); #endif - trayIconMenu->addAction(sendCoinsMenuAction); - trayIconMenu->addAction(receiveCoinsMenuAction); - trayIconMenu->addSeparator(); - trayIconMenu->addAction(signMessageAction); - trayIconMenu->addAction(verifyMessageAction); - trayIconMenu->addSeparator(); + if (enableWallet) { + trayIconMenu->addAction(sendCoinsMenuAction); + trayIconMenu->addAction(receiveCoinsMenuAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(signMessageAction); + trayIconMenu->addAction(verifyMessageAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(openRPCConsoleAction); + } trayIconMenu->addAction(optionsAction); - trayIconMenu->addAction(openRPCConsoleAction); #ifndef Q_OS_MAC // This is built-in on Mac trayIconMenu->addSeparator(); trayIconMenu->addAction(quitAction); From 42a995ae4819ea472b211eb5088727a422fcbeb8 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sun, 7 Oct 2018 09:30:45 +0900 Subject: [PATCH 094/263] [tests] Remove rpc_zmq.py rpc_zmq.py is racy and fails intermittently. Remove that test file and move the getzmqnotifications RPC test into interface_zmq.py --- test/functional/interface_zmq.py | 16 +++++++++++--- test/functional/rpc_zmq.py | 37 -------------------------------- test/functional/test_runner.py | 1 - 3 files changed, 13 insertions(+), 41 deletions(-) delete mode 100755 test/functional/rpc_zmq.py diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 1c518eab75..2f33fee005 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -14,6 +14,7 @@ ) from io import BytesIO +ADDRESS = "tcp://127.0.0.1:28332" class ZMQSubscriber: def __init__(self, socket, topic): @@ -51,11 +52,10 @@ def setup_nodes(self): # that this test fails if the publishing order changes. # Note that the publishing order is not defined in the documentation and # is subject to change. - address = "tcp://127.0.0.1:28332" self.zmq_context = zmq.Context() socket = self.zmq_context.socket(zmq.SUB) socket.set(zmq.RCVTIMEO, 60000) - socket.connect(address) + socket.connect(ADDRESS) # Subscribe to all available topics. self.hashblock = ZMQSubscriber(socket, b"hashblock") @@ -64,7 +64,7 @@ def setup_nodes(self): self.rawtx = ZMQSubscriber(socket, b"rawtx") self.extra_args = [ - ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], + ["-zmqpub%s=%s" % (sub.topic.decode(), ADDRESS) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], [], ] self.add_nodes(self.num_nodes, self.extra_args) @@ -117,5 +117,15 @@ def _zmq_test(self): hex = self.rawtx.receive() assert_equal(payment_txid, bytes_to_hex_str(hash256(hex))) + self.log.info("Test the getzmqnotifications RPC") + assert_equal(self.nodes[0].getzmqnotifications(), [ + {"type": "pubhashblock", "address": ADDRESS}, + {"type": "pubhashtx", "address": ADDRESS}, + {"type": "pubrawblock", "address": ADDRESS}, + {"type": "pubrawtx", "address": ADDRESS}, + ]) + + assert_equal(self.nodes[1].getzmqnotifications(), []) + if __name__ == '__main__': ZMQTest().main() diff --git a/test/functional/rpc_zmq.py b/test/functional/rpc_zmq.py deleted file mode 100755 index bfa6b06f67..0000000000 --- a/test/functional/rpc_zmq.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/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 for the ZMQ RPC methods.""" - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal - - -class RPCZMQTest(BitcoinTestFramework): - - address = "tcp://127.0.0.1:28332" - - def set_test_params(self): - self.num_nodes = 1 - self.setup_clean_chain = True - - def skip_test_if_missing_module(self): - self.skip_if_no_py3_zmq() - self.skip_if_no_bitcoind_zmq() - - def run_test(self): - self._test_getzmqnotifications() - - def _test_getzmqnotifications(self): - self.restart_node(0, extra_args=[]) - assert_equal(self.nodes[0].getzmqnotifications(), []) - - self.restart_node(0, extra_args=["-zmqpubhashtx=%s" % self.address]) - assert_equal(self.nodes[0].getzmqnotifications(), [ - {"type": "pubhashtx", "address": self.address}, - ]) - - -if __name__ == '__main__': - RPCZMQTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index d9960460d9..c6d1574201 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -152,7 +152,6 @@ 'feature_versionbits_warning.py', 'rpc_preciousblock.py', 'wallet_importprunedfunds.py', - 'rpc_zmq.py', 'rpc_signmessage.py', 'feature_nulldummy.py', 'mempool_accept.py', From 64937fda628500203f1281098ddbff6818425a5b Mon Sep 17 00:00:00 2001 From: Damian Mee Date: Sun, 7 Oct 2018 11:16:22 +0900 Subject: [PATCH 095/263] [docs] path to descriptors.md fixed --- doc/release-notes/release-notes-0.17.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release-notes/release-notes-0.17.0.md b/doc/release-notes/release-notes-0.17.0.md index ce7a1f6ac1..418d7ba5f9 100644 --- a/doc/release-notes/release-notes-0.17.0.md +++ b/doc/release-notes/release-notes-0.17.0.md @@ -270,7 +270,7 @@ Low-level RPC changes - The new RPC `scantxoutset` can be used to scan the UTXO set for entries that match certain output descriptors. Refer to the [output descriptors - reference documentation](doc/descriptors.md) for more details. This call + reference documentation](/doc/descriptors.md) for more details. This call is similar to `listunspent` but does not use a wallet, meaning that the wallet can be disabled at compile or run time. This call is experimental, as such, is subject to changes or removal in future releases. From 0bd64dc6d60af45e19465f23fac3dd425345a0cb Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 8 Oct 2018 00:41:40 +0300 Subject: [PATCH 096/263] Fix macOS files description --- src/qt/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/README.md b/src/qt/README.md index 3ec538b4f4..0eb18f7cd5 100644 --- a/src/qt/README.md +++ b/src/qt/README.md @@ -64,8 +64,8 @@ Represents the view to a single wallet. * `callback.h` * `guiconstants.h`: UI colors, app name, etc * `guiutil.h`: several helper functions -* `macdockiconhandler.(h/cpp)` -* `macdockiconhandler.(h/cpp)`: display notifications in macOS +* `macdockiconhandler.(h/mm)`: macOS dock icon handler +* `macnotificationhandler.(h/mm)`: display notifications in macOS ## Contribute From 62c304ea481d474bc87d950e21907b8b05134fe7 Mon Sep 17 00:00:00 2001 From: Chun Kuan Lee Date: Sat, 6 Oct 2018 13:42:11 +0800 Subject: [PATCH 097/263] tests: Allow closed http server in assert_start_raises_init_error --- test/functional/test_framework/test_node.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 7ab7fcfcb4..c05988c661 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -187,7 +187,9 @@ def wait_for_rpc_connection(self): if e.errno != errno.ECONNREFUSED: # Port not yet open? raise # unknown IO error except JSONRPCException as e: # Initialization phase - if e.error['code'] != -28: # RPC in warmup? + # -28 RPC in warmup + # -342 Service unavailable, RPC server started but is shutting down due to error + if e.error['code'] != -28 and e.error['code'] != -342: raise # unknown JSON RPC exception except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting if "No RPC credentials" not in str(e): From 2f6b466aeb6d4c88ab2e0e8b2a402be0743608b5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 6 Oct 2018 03:33:24 -0700 Subject: [PATCH 098/263] Stop requiring imported pubkey to sign non-PKH schemes --- src/script/sign.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/script/sign.cpp b/src/script/sign.cpp index d779910425..0042f35e2e 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -73,15 +73,18 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c return false; } -static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion) +static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion) { + CKeyID keyid = pubkey.GetID(); const auto it = sigdata.signatures.find(keyid); if (it != sigdata.signatures.end()) { sig_out = it->second.second; return true; } - CPubKey pubkey; - GetPubKey(provider, sigdata, keyid, pubkey); + KeyOriginInfo info; + if (provider.GetKeyOrigin(keyid, info)) { + sigdata.misc_pubkeys.emplace(keyid, std::make_pair(pubkey, std::move(info))); + } if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) { auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out)); assert(i.second); @@ -114,15 +117,15 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: - if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false; + if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false; ret.push_back(std::move(sig)); return true; case TX_PUBKEYHASH: { CKeyID keyID = CKeyID(uint160(vSolutions[0])); - if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false; - ret.push_back(std::move(sig)); CPubKey pubkey; GetPubKey(provider, sigdata, keyID, pubkey); + if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) return false; + ret.push_back(std::move(sig)); ret.push_back(ToByteVector(pubkey)); return true; } @@ -138,7 +141,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator ret.push_back(valtype()); // workaround CHECKMULTISIG bug for (size_t i = 1; i < vSolutions.size() - 1; ++i) { CPubKey pubkey = CPubKey(vSolutions[i]); - if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) { + if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) { ret.push_back(std::move(sig)); } } From 2ab9140c92c7ffd950f9ea6e1e78107a217bb336 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 6 Oct 2018 00:05:51 +0300 Subject: [PATCH 099/263] Add tooltips for both datadir and blocksdir --- src/qt/forms/debugwindow.ui | 6 ++++++ src/qt/rpcconsole.cpp | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 322a84ee92..dca16d6f78 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -127,6 +127,9 @@ IBeamCursor + + To specify a non-default location of the data directory use the '%1' option. + N/A @@ -153,6 +156,9 @@ IBeamCursor + + To specify a non-default location of the blocks directory use the '%1' option. + N/A diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 5bf9893141..7ec4feabfb 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -459,6 +459,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center()); } + QChar nonbreaking_hyphen(8209); + ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir")); + ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir")); ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME))); if (platformStyle->getImagesOnButtons()) { From 3e9f6c821beb58f882356141efe9140e66d00c0d Mon Sep 17 00:00:00 2001 From: practicalswift Date: Mon, 8 Oct 2018 15:50:09 +0200 Subject: [PATCH 100/263] Add missing locks and locking annotations for CAddrMan --- src/addrman.h | 53 +++++++++++++++++++------------------- src/test/addrman_tests.cpp | 4 +++ 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/addrman.h b/src/addrman.h index a36f7ea100..d220e763b3 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -187,36 +187,37 @@ class CAddrInfo : public CAddress */ class CAddrMan { -private: +protected: //! critical section to protect the inner data structures mutable CCriticalSection cs; +private: //! last used nId - int nIdCount; + int nIdCount GUARDED_BY(cs); //! table with information about all nIds - std::map mapInfo; + std::map mapInfo GUARDED_BY(cs); //! find an nId based on its network address - std::map mapAddr; + std::map mapAddr GUARDED_BY(cs); //! randomly-ordered vector of all nIds - std::vector vRandom; + std::vector vRandom GUARDED_BY(cs); // number of "tried" entries - int nTried; + int nTried GUARDED_BY(cs); //! list of "tried" buckets - int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; + int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); //! number of (unique) "new" entries - int nNew; + int nNew GUARDED_BY(cs); //! list of "new" buckets - int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; + int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); //! last time Good was called (memory only) - int64_t nLastGood; + int64_t nLastGood GUARDED_BY(cs); //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions. std::set m_tried_collisions; @@ -229,58 +230,58 @@ class CAddrMan FastRandomContext insecure_rand; //! Find an entry. - CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr); + CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); //! find an entry, creating it if necessary. //! nTime and nServices of the found node are updated, if necessary. - CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr); + CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Swap two elements in vRandom. - void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2); + void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Move an entry from the "new" table(s) to the "tried" table - void MakeTried(CAddrInfo& info, int nId); + void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Delete an entry. It must not be in tried, and have refcount 0. - void Delete(int nId); + void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Clear a position in a "new" table. This is the only place where entries are actually deleted. - void ClearNew(int nUBucket, int nUBucketPos); + void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Mark an entry "good", possibly moving it from "new" to "tried". - void Good_(const CService &addr, bool test_before_evict, int64_t time); + void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Add an entry to the "new" table. - bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty); + bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Mark an entry as attempted to connect. - void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime); + void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. - CAddrInfo Select_(bool newOnly); + CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs); //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions. - void ResolveCollisions_(); + void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs); //! Return a random to-be-evicted tried table address. - CAddrInfo SelectTriedCollision_(); + CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs); //! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic. virtual int RandomInt(int nMax); #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. - int Check_(); + int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs); #endif //! Select several addresses at once. - void GetAddr_(std::vector &vAddr); + void GetAddr_(std::vector &vAddr) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Mark an entry as currently-connected-to. - void Connected_(const CService &addr, int64_t nTime); + void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Update an entry's service bits. - void SetServices_(const CService &addr, ServiceFlags nServices); + void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs); public: /** diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index ee3650d148..fbe438092e 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -40,22 +40,26 @@ class CAddrManTest : public CAddrMan CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr) { + LOCK(cs); return CAddrMan::Find(addr, pnId); } CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr) { + LOCK(cs); return CAddrMan::Create(addr, addrSource, pnId); } void Delete(int nId) { + LOCK(cs); CAddrMan::Delete(nId); } // Simulates connection failure so that we can test eviction of offline nodes void SimConnFail(CService& addr) { + LOCK(cs); int64_t nLastSuccess = 1; Good_(addr, true, nLastSuccess); // Set last good connection in the deep past. From 9dcf6c0dfec51f2a49edef537f377422d6dbdceb Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 6 Nov 2017 19:12:47 +0100 Subject: [PATCH 101/263] build: Add --disable-bip70 configure option This patch adds a --disable-bip70 configure option that disables BIP70 payment request support. When disabled, this removes the dependency of the GUI on OpenSSL and Protobuf. --- configure.ac | 26 +++++++++++++++++++++-- src/Makefile.am | 2 ++ src/Makefile.qt.include | 15 +++++++++++-- src/Makefile.qttest.include | 14 +++++++++---- src/qt/bitcoin.cpp | 6 +++++- src/qt/coincontroldialog.cpp | 5 +++++ src/qt/paymentserver.cpp | 35 ++++++++++++++++++++++++++++++- src/qt/paymentserver.h | 20 ++++++++++++++++++ src/qt/sendcoinsdialog.cpp | 8 +++++++ src/qt/sendcoinsentry.cpp | 10 +++++++++ src/qt/test/compattests.cpp | 6 ++++++ src/qt/test/test_main.cpp | 6 ++++-- src/qt/test/wallettests.cpp | 1 + src/qt/transactiondesc.cpp | 6 ++++++ src/qt/utilitydialog.cpp | 2 ++ src/qt/walletmodel.cpp | 13 +++++++++++- src/qt/walletmodel.h | 16 ++++++++++++++ src/qt/walletmodeltransaction.cpp | 6 ++++++ src/qt/walletmodeltransaction.h | 1 + 19 files changed, 185 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 72bd785e2e..7141a9a03a 100644 --- a/configure.ac +++ b/configure.ac @@ -209,6 +209,11 @@ AC_ARG_ENABLE([zmq], [disable ZMQ notifications])], [use_zmq=$enableval], [use_zmq=yes]) +AC_ARG_ENABLE([bip70], + [AS_HELP_STRING([--disable-bip70], + [disable BIP70 (payment protocol) support in GUI (enabled by default)])], + [enable_bip70=$enableval], + [enable_bip70=yes]) AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) @@ -1082,7 +1087,9 @@ if test x$use_pkgconfig = xyes; then [ PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)]) PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)]) - BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])]) + if test x$enable_bip70 != xno; then + BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])]) + fi if test x$use_qr != xno; then BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) fi @@ -1142,7 +1149,9 @@ else esac fi - BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], BITCOIN_QT_FAIL(libprotobuf not found))) + if test x$enable_bip70 != xno; then + BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], BITCOIN_QT_FAIL(libprotobuf not found))) + fi if test x$use_qr != xno; then BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])]) BITCOIN_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)]) @@ -1220,7 +1229,9 @@ AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes]) AC_SUBST(UNIVALUE_CFLAGS) AC_SUBST(UNIVALUE_LIBS) +if test x$enable_bip70 != xno; then BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path) +fi AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) @@ -1338,6 +1349,15 @@ if test x$bitcoin_enable_qt != xno; then else AC_MSG_RESULT([no]) fi + + AC_MSG_CHECKING([whether to build BIP70 support]) + if test x$enable_bip70 != xno; then + AC_DEFINE([ENABLE_BIP70],[1],[Define if BIP70 support should be compiled in]) + enable_bip70=yes + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi fi AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) @@ -1369,6 +1389,7 @@ AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) +AM_CONDITIONAL([ENABLE_BIP70],[test x$enable_bip70 = xyes]) AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) @@ -1503,6 +1524,7 @@ echo "Options used to compile and link:" echo " with wallet = $enable_wallet" echo " with gui / qt = $bitcoin_enable_qt" if test x$bitcoin_enable_qt != xno; then + echo " with bip70 = $enable_bip70" echo " with qr = $use_qr" fi echo " with zmq = $use_zmq" diff --git a/src/Makefile.am b/src/Makefile.am index 7a2e9fa5e8..6141919007 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -587,9 +587,11 @@ if HARDEN $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) endif +if ENABLE_BIP70 %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(setCurrentWallet(walletModel->getWalletName()); } +#ifdef ENABLE_BIP70 connect(walletModel, &WalletModel::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK); +#endif connect(walletModel, &WalletModel::unload, this, &BitcoinApplication::removeWallet); m_wallet_models.push_back(walletModel); @@ -468,7 +470,9 @@ void BitcoinApplication::initializeResult(bool success) // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete qWarning() << "Platform customization:" << platformStyle->getName(); #ifdef ENABLE_WALLET +#ifdef ENABLE_BIP70 PaymentServer::LoadRootCAs(); +#endif paymentServer->setOptionsModel(optionsModel); #endif @@ -537,7 +541,7 @@ WId BitcoinApplication::getMainWinId() const static void SetupUIArgs() { -#ifdef ENABLE_WALLET +#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70) gArgs.AddArg("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS), true, OptionsCategory::GUI); #endif gArgs.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), false, OptionsCategory::GUI); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 68330c51fa..ea970c0bc9 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -2,10 +2,15 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include #include +#include #include #include #include diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index bcafc8f859..760728f85b 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include @@ -45,6 +49,7 @@ const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds const QString BITCOIN_IPC_PREFIX("bitcoin:"); +#ifdef ENABLE_BIP70 // BIP70 payment protocol messages const char* BIP70_MESSAGE_PAYMENTACK = "PaymentACK"; const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest"; @@ -67,6 +72,7 @@ namespace // Anon namespace { std::unique_ptr certStore; } +#endif // // Create a name that is unique for: @@ -93,6 +99,7 @@ static QString ipcServerName() static QList savedPaymentRequests; +#ifdef ENABLE_BIP70 static void ReportInvalidCertificate(const QSslCertificate& cert) { qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName); @@ -180,6 +187,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) // or use Qt's blacklist? // "certificate stapling" with server-side caching is more efficient } +#endif // // Sending to the server is done synchronously, at startup. @@ -221,6 +229,7 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char* } } } +#ifdef ENABLE_BIP70 else if (QFile::exists(arg)) // Filename { savedPaymentRequests.append(arg); @@ -244,6 +253,7 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char* // GUI hasn't started yet so we can't pop up a message box. qWarning() << "PaymentServer::ipcSendCommandLine: Payment request file does not exist: " << arg; } +#endif } } @@ -290,12 +300,16 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(parent), saveURIs(true), uriServer(0), +#ifdef ENABLE_BIP70 netManager(0), +#endif optionsModel(0) { +#ifdef ENABLE_BIP70 // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; +#endif // Install global event filter to catch QFileOpenEvents // on Mac: sent when you click bitcoin: links @@ -319,14 +333,18 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : } else { connect(uriServer, &QLocalServer::newConnection, this, &PaymentServer::handleURIConnection); +#ifdef ENABLE_BIP70 connect(this, &PaymentServer::receivedPaymentACK, this, &PaymentServer::handlePaymentACK); +#endif } } } PaymentServer::~PaymentServer() { +#ifdef ENABLE_BIP70 google::protobuf::ShutdownProtobufLibrary(); +#endif } // @@ -349,6 +367,7 @@ bool PaymentServer::eventFilter(QObject *object, QEvent *event) return QObject::eventFilter(object, event); } +#ifdef ENABLE_BIP70 void PaymentServer::initNetManager() { if (!optionsModel) @@ -372,10 +391,13 @@ void PaymentServer::initNetManager() connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished); connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors); } +#endif void PaymentServer::uiReady() { +#ifdef ENABLE_BIP70 initNetManager(); +#endif saveURIs = false; for (const QString& s : savedPaymentRequests) @@ -403,6 +425,7 @@ void PaymentServer::handleURIOrFile(const QString& s) QUrlQuery uri((QUrl(s))); if (uri.hasQueryItem("r")) // payment request URI { +#ifdef ENABLE_BIP70 QByteArray temp; temp.append(uri.queryItemValue("r")); QString decoded = QUrl::fromPercentEncoding(temp); @@ -420,7 +443,11 @@ void PaymentServer::handleURIOrFile(const QString& s) tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()), CClientUIInterface::ICON_WARNING); } - +#else + Q_EMIT message(tr("URI handling"), + tr("Cannot process payment request because BIP70 support was not compiled in."), + CClientUIInterface::ICON_WARNING); +#endif return; } else // normal URI @@ -444,6 +471,7 @@ void PaymentServer::handleURIOrFile(const QString& s) } } +#ifdef ENABLE_BIP70 if (QFile::exists(s)) // payment request file { PaymentRequestPlus request; @@ -459,6 +487,7 @@ void PaymentServer::handleURIOrFile(const QString& s) return; } +#endif } void PaymentServer::handleURIConnection() @@ -481,6 +510,7 @@ void PaymentServer::handleURIConnection() handleURIOrFile(msg); } +#ifdef ENABLE_BIP70 // // Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine() // so don't use "Q_EMIT message()", but "QMessageBox::"! @@ -730,12 +760,14 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList } Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); } +#endif void PaymentServer::setOptionsModel(OptionsModel *_optionsModel) { this->optionsModel = _optionsModel; } +#ifdef ENABLE_BIP70 void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) { // currently we don't further process or store the paymentACK message @@ -794,3 +826,4 @@ X509_STORE* PaymentServer::getCertStore() { return certStore.get(); } +#endif diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index d335db9c85..eba195e3bd 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -32,7 +32,13 @@ // sends them to the server. // +#if defined(HAVE_CONFIG_H) +#include +#endif + +#ifdef ENABLE_BIP70 #include +#endif #include #include @@ -73,6 +79,7 @@ class PaymentServer : public QObject explicit PaymentServer(QObject* parent, bool startLocalServer = true); ~PaymentServer(); +#ifdef ENABLE_BIP70 // Load root certificate authorities. Pass nullptr (default) // to read from the file specified in the -rootcertificates setting, // or, if that's not set, to use the system default root certificates. @@ -82,10 +89,12 @@ class PaymentServer : public QObject // Return certificate store static X509_STORE* getCertStore(); +#endif // OptionsModel is used for getting proxy settings and display unit void setOptionsModel(OptionsModel *optionsModel); +#ifdef ENABLE_BIP70 // Verify that the payment request network matches the client network static bool verifyNetwork(interfaces::Node& node, const payments::PaymentDetails& requestDetails); // Verify if the payment request is expired @@ -94,13 +103,16 @@ class PaymentServer : public QObject static bool verifySize(qint64 requestSize); // Verify the payment request amount is valid static bool verifyAmount(const CAmount& requestAmount); +#endif Q_SIGNALS: // Fired when a valid payment request is received void receivedPaymentRequest(SendCoinsRecipient); +#ifdef ENABLE_BIP70 // Fired when a valid PaymentACK is received void receivedPaymentACK(const QString &paymentACKMsg); +#endif // Fired when a message should be reported to the user void message(const QString &title, const QString &message, unsigned int style); @@ -110,17 +122,21 @@ public Q_SLOTS: // to display payment requests to the user void uiReady(); +#ifdef ENABLE_BIP70 // Submit Payment message to a merchant, get back PaymentACK: void fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction); +#endif // Handle an incoming URI, URI with local file scheme or file void handleURIOrFile(const QString& s); private Q_SLOTS: void handleURIConnection(); +#ifdef ENABLE_BIP70 void netRequestFinished(QNetworkReply*); void reportSslErrors(QNetworkReply*, const QList &); void handlePaymentACK(const QString& paymentACKMsg); +#endif protected: // Constructor registers this on the parent QApplication to @@ -128,17 +144,21 @@ private Q_SLOTS: bool eventFilter(QObject *object, QEvent *event); private: +#ifdef ENABLE_BIP70 static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request); bool processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient); void fetchRequest(const QUrl& url); // Setup networking void initNetManager(); +#endif bool saveURIs; // true during startup QLocalServer* uriServer; +#ifdef ENABLE_BIP70 QNetworkAccessManager* netManager; // Used to fetch payment requests +#endif OptionsModel *optionsModel; }; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 6f66bc19e1..858128f9f9 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include @@ -290,7 +294,9 @@ void SendCoinsDialog::on_sendButton_clicked() QString recipientElement; recipientElement = "
    "; +#ifdef ENABLE_BIP70 if (!rcp.paymentRequest.IsInitialized()) // normal payment +#endif { if(rcp.label.length() > 0) // label with address { @@ -302,6 +308,7 @@ void SendCoinsDialog::on_sendButton_clicked() recipientElement.append(tr("%1 to %2").arg(amount, address)); } } +#ifdef ENABLE_BIP70 else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request { recipientElement.append(tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant))); @@ -310,6 +317,7 @@ void SendCoinsDialog::on_sendButton_clicked() { recipientElement.append(tr("%1 to %2").arg(amount, address)); } +#endif formatted.append(recipientElement); } diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index b394ff3150..76c942c8b9 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include @@ -133,9 +137,11 @@ bool SendCoinsEntry::validate(interfaces::Node& node) // Check input validity bool retval = true; +#ifdef ENABLE_BIP70 // Skip checks for payment request if (recipient.paymentRequest.IsInitialized()) return retval; +#endif if (!model->validateAddress(ui->payTo->text())) { @@ -166,9 +172,11 @@ bool SendCoinsEntry::validate(interfaces::Node& node) SendCoinsRecipient SendCoinsEntry::getValue() { +#ifdef ENABLE_BIP70 // Payment request if (recipient.paymentRequest.IsInitialized()) return recipient; +#endif // Normal payment recipient.address = ui->payTo->text(); @@ -196,6 +204,7 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) { recipient = value; +#ifdef ENABLE_BIP70 if (recipient.paymentRequest.IsInitialized()) // payment request { if (recipient.authenticatedMerchant.isEmpty()) // unauthenticated @@ -216,6 +225,7 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) } } else // normal payment +#endif { // message ui->messageTextLabel->setText(recipient.message); diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp index af5c69ea9a..6750c543da 100644 --- a/src/qt/test/compattests.cpp +++ b/src/qt/test/compattests.cpp @@ -2,7 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + +#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70) #include // this includes protobuf's port.h which defines its own bswap macos +#endif #include diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index df65a85fb5..28df4ebf26 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -14,9 +14,11 @@ #ifdef ENABLE_WALLET #include +#ifdef ENABLE_BIP70 #include +#endif // ENABLE_BIP70 #include -#endif +#endif // ENABLE_WALLET #include #include @@ -74,7 +76,7 @@ int main(int argc, char *argv[]) if (QTest::qExec(&test1) != 0) { fInvalid = true; } -#ifdef ENABLE_WALLET +#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70) PaymentServerTests test2; if (QTest::qExec(&test2) != 0) { fInvalid = true; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index a0cfe8ae87..2284be4121 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 59332be754..3c5617bfa8 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include @@ -257,6 +261,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall if (r.first == "Message") strHTML += "
    " + tr("Message") + ":
    " + GUIUtil::HtmlEscape(r.second, true) + "
    "; +#ifdef ENABLE_BIP70 // // PaymentRequest info: // @@ -271,6 +276,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall strHTML += "" + tr("Merchant") + ": " + GUIUtil::HtmlEscape(merchant) + "
    "; } } +#endif if (wtx.is_coinbase) { diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 7d903b3b1c..faeed87ec4 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -14,7 +14,9 @@ #include #include #include +#ifdef ENABLE_BIP70 #include +#endif #include #include diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index f7cc94ae32..71b2d321e2 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + #include #include @@ -142,6 +146,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; +#ifdef ENABLE_BIP70 if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... CAmount subtotal = 0; @@ -164,6 +169,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact total += subtotal; } else +#endif { // User-entered bitcoin address / amount: if(!validateAddress(rcp.address)) { @@ -235,6 +241,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran std::vector> vOrderForm; for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { +#ifdef ENABLE_BIP70 if (rcp.paymentRequest.IsInitialized()) { // Make sure any payment requests involved are still valid. @@ -247,7 +254,9 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran rcp.paymentRequest.SerializeToString(&value); vOrderForm.emplace_back("PaymentRequest", std::move(value)); } - else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example) + else +#endif + if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example) vOrderForm.emplace_back("Message", rcp.message.toStdString()); } @@ -266,7 +275,9 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { // Don't touch the address book when we have a payment request +#ifdef ENABLE_BIP70 if (!rcp.paymentRequest.IsInitialized()) +#endif { std::string strAddress = rcp.address.toStdString(); CTxDestination dest = DecodeDestination(strAddress); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index b22728c69b..ec4c5a2a6c 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -10,7 +10,13 @@ #include #include