diff options
Diffstat (limited to 'test')
23 files changed, 396 insertions, 91 deletions
diff --git a/test/README.md b/test/README.md index 9d4351b1de..ecea3213ab 100644 --- a/test/README.md +++ b/test/README.md @@ -13,8 +13,7 @@ bitcoin-tx. - [lint](/test/lint/) which perform various static analysis checks. The util tests are run as part of `make check` target. The functional -tests and lint scripts are run by the travis continuous build process whenever a pull -request is opened. All sets of tests can also be run locally. +tests and lint scripts can be run as explained in the sections below. # Running tests locally diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index fdb60fb0e8..d38eca6cbe 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -378,7 +378,7 @@ class BIP68Test(BitcoinTestFramework): add_witness_commitment(block) block.solve() - self.nodes[0].submitblock(block.serialize(True).hex()) + self.nodes[0].submitblock(block.serialize().hex()) assert_equal(self.nodes[0].getbestblockhash(), block.hash) def activateCSV(self): diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index 2b93e3c24d..f0d6bc21e6 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -21,6 +21,16 @@ class ConfArgsTest(BitcoinTestFramework): with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf: conf.write('includeconf={}\n'.format(inc_conf_file_path)) + self.nodes[0].assert_start_raises_init_error( + expected_msg='Error parsing command line arguments: Invalid parameter -dash_cli', + extra_args=['-dash_cli=1'], + ) + with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: + conf.write('dash_conf=1\n') + with self.nodes[0].assert_debug_log(expected_msgs=['Ignoring unknown configuration value dash_conf']): + self.start_node(0) + self.stop_node(0) + with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('-dash=1\n') self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -') @@ -61,9 +71,16 @@ class ConfArgsTest(BitcoinTestFramework): with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf: conf.write('') # clear + def test_log_buffer(self): + with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -connect=0']): + self.start_node(0, extra_args=['-noconnect=0']) + self.stop_node(0) + def run_test(self): self.stop_node(0) + self.test_log_buffer() + self.test_config_file_parser() # Remove the -datadir argument so it doesn't override the config file diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index a56c983ccc..60a703c48f 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -108,7 +108,7 @@ class NULLDUMMYTest(BitcoinTestFramework): witness and add_witness_commitment(block) block.rehash() block.solve() - node.submitblock(block.serialize(True).hex()) + node.submitblock(block.serialize().hex()) if (accept): assert_equal(node.getbestblockhash(), block.hash) self.tip = block.sha256 diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index e2b3b2d544..66c395d7a2 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -23,8 +23,6 @@ from test_framework.util import ( wait_until, ) -MIN_BLOCKS_TO_KEEP = 288 - # Rescans start at the earliest block up to 2 hours before a key timestamp, so # the manual prune RPC avoids pruning blocks in the same window to be # compatible with pruning based on key creation time. @@ -273,20 +271,9 @@ class PruneTest(BitcoinTestFramework): else: return index - def prune(index, expected_ret=None): + def prune(index): ret = node.pruneblockchain(height=height(index)) - # Check the return value. When use_timestamp is True, just check - # that the return value is less than or equal to the expected - # value, because when more than one block is generated per second, - # a timestamp will not be granular enough to uniquely identify an - # individual block. - if expected_ret is None: - expected_ret = index - if use_timestamp: - assert_greater_than(ret, 0) - assert_greater_than(expected_ret + 1, ret) - else: - assert_equal(ret, expected_ret) + assert_equal(ret, node.getblockchaininfo()['pruneheight']) def has_block(index): return os.path.isfile(os.path.join(self.nodes[node_number].datadir, "regtest", "blocks", "blk{:05}.dat".format(index))) @@ -326,7 +313,7 @@ class PruneTest(BitcoinTestFramework): assert not has_block(1), "blk00001.dat is still there, should be pruned by now" # height=1000 should not prune anything more, because tip-288 is in blk00002.dat. - prune(1000, 1001 - MIN_BLOCKS_TO_KEEP) + prune(1000) assert has_block(2), "blk00002.dat is still there, should be pruned by now" # advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat) diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index ccba547a1c..1496c5d958 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -64,7 +64,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): class ReplaceByFeeTest(BitcoinTestFramework): def set_test_params(self): - self.num_nodes = 2 + self.num_nodes = 1 self.extra_args = [ [ "-maxorphantx=1000", @@ -74,9 +74,6 @@ class ReplaceByFeeTest(BitcoinTestFramework): "-limitdescendantcount=200", "-limitdescendantsize=101", ], - [ - "-mempoolreplacement=0", - ], ] def skip_test_if_missing_module(self): @@ -148,16 +145,12 @@ class ReplaceByFeeTest(BitcoinTestFramework): # This will raise an exception due to insufficient fee assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, 0) - # This will raise an exception due to transaction replacement being disabled - assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, 0) # Extra 0.1 BTC fee tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] tx1b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))] tx1b_hex = txToHex(tx1b) - # Replacement still disabled even with "enough fee" - assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, 0) # Works when enabled tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0) @@ -168,11 +161,6 @@ class ReplaceByFeeTest(BitcoinTestFramework): assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid)) - # Second node is running mempoolreplacement=0, will not replace originally-seen txn - mempool = self.nodes[1].getrawmempool() - assert tx1a_txid in mempool - assert tx1b_txid not in mempool - def test_doublespend_chain(self): """Doublespend of a long chain""" diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 3ca6bec254..0994857912 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -10,7 +10,7 @@ Version 2 compact blocks are post-segwit (wtxids) import random from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment -from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_block, msg_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_witness_block, msg_witness_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex +from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex from test_framework.mininode import mininode_lock, P2PInterface from test_framework.script import CScript, OP_TRUE, OP_DROP from test_framework.test_framework import BitcoinTestFramework @@ -114,7 +114,7 @@ class CompactBlocksTest(BitcoinTestFramework): # Create 10 more anyone-can-spend utxo's for testing. def make_utxos(self): block = self.build_block_on_tip(self.nodes[0]) - self.segwit_node.send_and_ping(msg_block(block)) + self.segwit_node.send_and_ping(msg_no_witness_block(block)) assert int(self.nodes[0].getbestblockhash(), 16) == block.sha256 self.nodes[0].generatetoaddress(100, self.nodes[0].getnewaddress(address_type="bech32")) @@ -130,7 +130,7 @@ class CompactBlocksTest(BitcoinTestFramework): block2.vtx.append(tx) block2.hashMerkleRoot = block2.calc_merkle_root() block2.solve() - self.segwit_node.send_and_ping(msg_block(block2)) + self.segwit_node.send_and_ping(msg_no_witness_block(block2)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), block2.sha256) self.utxos.extend([[tx.sha256, i, out_value] for i in range(10)]) @@ -408,9 +408,9 @@ class CompactBlocksTest(BitcoinTestFramework): # Send the coinbase, and verify that the tip advances. if version == 2: - msg = msg_witness_blocktxn() - else: msg = msg_blocktxn() + else: + msg = msg_no_witness_blocktxn() msg.block_transactions.blockhash = block.sha256 msg.block_transactions.transactions = [block.vtx[0]] test_node.send_and_ping(msg) @@ -463,9 +463,9 @@ class CompactBlocksTest(BitcoinTestFramework): test_getblocktxn_response(comp_block, test_node, [1, 2, 3, 4, 5]) - msg_bt = msg_blocktxn() + msg_bt = msg_no_witness_blocktxn() if with_witness: - msg_bt = msg_witness_blocktxn() # serialize with witnesses + msg_bt = msg_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) @@ -554,9 +554,9 @@ class CompactBlocksTest(BitcoinTestFramework): # different peer provide the block further down, so that we're still # verifying that the block isn't marked bad permanently. This is good # enough for now. - msg = msg_blocktxn() + msg = msg_no_witness_blocktxn() if version == 2: - msg = msg_witness_blocktxn() + msg = msg_blocktxn() msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:]) test_node.send_and_ping(msg) @@ -571,9 +571,9 @@ class CompactBlocksTest(BitcoinTestFramework): # Deliver the block if version == 2: - test_node.send_and_ping(msg_witness_block(block)) - else: test_node.send_and_ping(msg_block(block)) + else: + test_node.send_and_ping(msg_no_witness_block(block)) assert_equal(int(node.getbestblockhash(), 16), block.sha256) def test_getblocktxn_handler(self, test_node): @@ -785,7 +785,7 @@ class CompactBlocksTest(BitcoinTestFramework): delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p())) assert int(node.getbestblockhash(), 16) != block.sha256 - msg = msg_blocktxn() + msg = msg_no_witness_blocktxn() msg.block_transactions.blockhash = block.sha256 msg.block_transactions.transactions = block.vtx[1:] stalling_peer.send_and_ping(msg) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index df0f9fa365..b7fa42f593 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -25,12 +25,12 @@ from test_framework.messages import ( MSG_WITNESS_FLAG, NODE_NETWORK, NODE_WITNESS, - msg_block, + msg_no_witness_block, msg_getdata, msg_headers, msg_inv, msg_tx, - msg_witness_block, + msg_block, msg_witness_tx, ser_uint256, ser_vector, @@ -111,7 +111,7 @@ def get_virtual_size(witness_block): Virtual size is base + witness/4.""" base_size = len(witness_block.serialize(with_witness=False)) - total_size = len(witness_block.serialize(with_witness=True)) + total_size = len(witness_block.serialize()) # the "+3" is so we round up vsize = int((3 * base_size + total_size + 3) / 4) return vsize @@ -134,7 +134,7 @@ def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=Non - use the getbestblockhash rpc to check for acceptance.""" reason = [reason] if reason else [] with node.assert_debug_log(expected_msgs=reason): - p2p.send_message(msg_witness_block(block) if with_witness else msg_block(block)) + p2p.send_message(msg_block(block) if with_witness else msg_no_witness_block(block)) p2p.sync_with_ping() assert_equal(node.getbestblockhash() == block.hash, accepted) @@ -298,7 +298,7 @@ class SegWitTest(BitcoinTestFramework): block = self.build_next_block(version=1) block.solve() - self.test_node.send_message(msg_block(block)) + self.test_node.send_message(msg_no_witness_block(block)) self.test_node.sync_with_ping() # make sure the block was processed txid = block.vtx[0].sha256 @@ -345,7 +345,7 @@ class SegWitTest(BitcoinTestFramework): # But it should not be permanently marked bad... # Resend without witness information. - self.test_node.send_message(msg_block(block)) + self.test_node.send_message(msg_no_witness_block(block)) self.test_node.sync_with_ping() assert_equal(self.nodes[0].getbestblockhash(), block.hash) @@ -403,7 +403,7 @@ class SegWitTest(BitcoinTestFramework): block_hash = int(block_hash, 16) block = self.test_node.request_block(block_hash, 2) wit_block = self.test_node.request_block(block_hash, 2 | MSG_WITNESS_FLAG) - assert_equal(block.serialize(True), wit_block.serialize(True)) + assert_equal(block.serialize(), wit_block.serialize()) assert_equal(block.serialize(), hex_str_to_bytes(rpc_block)) else: # After activation, witness blocks and non-witness blocks should @@ -419,15 +419,15 @@ class SegWitTest(BitcoinTestFramework): rpc_block = self.nodes[0].getblock(block.hash, False) non_wit_block = self.test_node.request_block(block.sha256, 2) wit_block = self.test_node.request_block(block.sha256, 2 | MSG_WITNESS_FLAG) - assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block)) + assert_equal(wit_block.serialize(), hex_str_to_bytes(rpc_block)) assert_equal(wit_block.serialize(False), non_wit_block.serialize()) - assert_equal(wit_block.serialize(True), block.serialize(True)) + assert_equal(wit_block.serialize(), block.serialize()) # Test size, vsize, weight rpc_details = self.nodes[0].getblock(block.hash, True) - assert_equal(rpc_details["size"], len(block.serialize(True))) + assert_equal(rpc_details["size"], len(block.serialize())) assert_equal(rpc_details["strippedsize"], len(block.serialize(False))) - weight = 3 * len(block.serialize(False)) + len(block.serialize(True)) + weight = 3 * len(block.serialize(False)) + len(block.serialize()) assert_equal(rpc_details["weight"], weight) # Upgraded node should not ask for blocks from unupgraded @@ -791,7 +791,7 @@ class SegWitTest(BitcoinTestFramework): block.solve() # Test the test -- witness serialization should be different - assert msg_witness_block(block).serialize() != msg_block(block).serialize() + assert msg_block(block).serialize() != msg_no_witness_block(block).serialize() # This empty block should be valid. test_witness_block(self.nodes[0], self.test_node, block, accepted=True) @@ -884,13 +884,13 @@ class SegWitTest(BitcoinTestFramework): # We can't send over the p2p network, because this is too big to relay # TODO: repeat this test with a block that can be relayed - self.nodes[0].submitblock(block.serialize(True).hex()) + self.nodes[0].submitblock(block.serialize().hex()) assert self.nodes[0].getbestblockhash() != block.hash block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop() assert get_virtual_size(block) < MAX_BLOCK_BASE_SIZE - self.nodes[0].submitblock(block.serialize(True).hex()) + self.nodes[0].submitblock(block.serialize().hex()) assert self.nodes[0].getbestblockhash() == block.hash @@ -969,7 +969,7 @@ class SegWitTest(BitcoinTestFramework): assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1) # Make sure that our test case would exceed the old max-network-message # limit - assert len(block.serialize(True)) > 2 * 1024 * 1024 + assert len(block.serialize()) > 2 * 1024 * 1024 test_witness_block(self.nodes[0], self.test_node, block, accepted=False) @@ -997,14 +997,14 @@ class SegWitTest(BitcoinTestFramework): add_witness_commitment(block, nonce=1) block.vtx[0].wit = CTxWitness() # drop the nonce block.solve() - self.nodes[0].submitblock(block.serialize(True).hex()) + self.nodes[0].submitblock(block.serialize().hex()) assert self.nodes[0].getbestblockhash() != block.hash # Now redo commitment with the standard nonce, but let bitcoind fill it in. add_witness_commitment(block, nonce=0) block.vtx[0].wit = CTxWitness() block.solve() - self.nodes[0].submitblock(block.serialize(True).hex()) + self.nodes[0].submitblock(block.serialize().hex()) assert_equal(self.nodes[0].getbestblockhash(), block.hash) # This time, add a tx with non-empty witness, but don't supply @@ -1019,7 +1019,7 @@ class SegWitTest(BitcoinTestFramework): block_2.vtx[0].vout.pop() block_2.vtx[0].wit = CTxWitness() - self.nodes[0].submitblock(block_2.serialize(True).hex()) + self.nodes[0].submitblock(block_2.serialize().hex()) # Tip should not advance! assert self.nodes[0].getbestblockhash() != block_2.hash diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 7abcd71bb8..58010f7c2e 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -7,9 +7,13 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_raises_rpc_error, + assert_equal, ) -import decimal +from test_framework.key import ECPubKey +import binascii +import decimal +import itertools class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): @@ -44,6 +48,30 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.checkbalances() + # Test mixed compressed and uncompressed pubkeys + self.log.info('Mixed compressed and uncompressed multisigs are not allowed') + pk0 = node0.getaddressinfo(node0.getnewaddress())['pubkey'] + pk1 = node1.getaddressinfo(node1.getnewaddress())['pubkey'] + pk2 = node2.getaddressinfo(node2.getnewaddress())['pubkey'] + + # decompress pk2 + pk_obj = ECPubKey() + pk_obj.set(binascii.unhexlify(pk2)) + pk_obj.compressed = False + pk2 = binascii.hexlify(pk_obj.get_bytes()).decode() + + # Check all permutations of keys because order matters apparently + for keys in itertools.permutations([pk0, pk1, pk2]): + # Results should be the same as this legacy one + legacy_addr = node0.createmultisig(2, keys, 'legacy')['address'] + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address']) + + # Generate addresses with the segwit types. These should all make legacy addresses + assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address']) + assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address']) + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address']) + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address']) + def check_addmultisigaddress_errors(self): self.log.info('Check that addmultisigaddress fails when the private keys are missing') addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)] diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index d89fd6461f..cdf636e200 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -662,6 +662,7 @@ class RawTransactionsTest(BitcoinTestFramework): result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee) result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee}) result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10*min_relay_tx_fee}) + assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1}) result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex']) assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate) assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 8a7ea7aa58..8bfa7a0238 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -9,6 +9,7 @@ from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + assert_greater_than, assert_raises_rpc_error, connect_nodes_bi, disconnect_nodes, @@ -129,6 +130,15 @@ class PSBTTest(BitcoinTestFramework): assert_equal(walletprocesspsbt_out['complete'], True) self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex']) + # feeRate of 0.1 BTC / KB produces a total fee slightly below -maxtxfee (~0.05280000): + res = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 0.1}) + assert_greater_than(res["fee"], 0.05) + assert_greater_than(0.06, res["fee"]) + + # feeRate of 10 BTC / KB produces a total fee well above -maxtxfee + # previously this was silenty capped at -maxtxfee + assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10}) + # partially sign multisig things with node 1 psbtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt'] walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx) @@ -152,9 +162,10 @@ class PSBTTest(BitcoinTestFramework): # Make sure that a non-psbt with signatures cannot be converted # Error could be either "TX decode failed" (segwit inputs causes parsing to fail) or "Inputs must not have scriptSigs and scriptWitnesses" + # We must set iswitness=True because the serialized transaction has inputs and is therefore a witness transaction signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex']) - assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, signedtx['hex']) - assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, signedtx['hex'], False) + assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], iswitness=True) + assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], permitsigdata=False, iswitness=True) # Unless we allow it to convert and strip signatures self.nodes[0].converttopsbt(signedtx['hex'], True) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 954ae3c4df..e454ed5987 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -1130,7 +1130,7 @@ class msg_block: self.block.deserialize(f) def serialize(self): - return self.block.serialize(with_witness=False) + return self.block.serialize() def __repr__(self): return "msg_block(block=%s)" % (repr(self.block)) @@ -1152,11 +1152,10 @@ class msg_generic: return "msg_generic()" -class msg_witness_block(msg_block): +class msg_no_witness_block(msg_block): __slots__ = () def serialize(self): - r = self.block.serialize(with_witness=True) - return r + return self.block.serialize(with_witness=False) class msg_getaddr: @@ -1442,17 +1441,15 @@ class msg_blocktxn: def serialize(self): r = b"" - r += self.block_transactions.serialize(with_witness=False) + r += self.block_transactions.serialize() return r def __repr__(self): return "msg_blocktxn(block_transactions=%s)" % (repr(self.block_transactions)) -class msg_witness_blocktxn(msg_blocktxn): +class msg_no_witness_blocktxn(msg_blocktxn): __slots__ = () def serialize(self): - r = b"" - r += self.block_transactions.serialize(with_witness=True) - return r + return self.block_transactions.serialize(with_witness=False) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 80dced733e..462547f44f 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -67,14 +67,14 @@ TEST_EXIT_PASSED = 0 TEST_EXIT_SKIPPED = 77 EXTENDED_SCRIPTS = [ - # These tests are not run by the travis build process. + # These tests are not run by default. # Longest test should go first, to favor running tests in parallel 'feature_pruning.py', 'feature_dbcrash.py', ] BASE_SCRIPTS = [ - # Scripts that are run by the travis build process. + # Scripts that are run by default. # Longest test should go first, to favor running tests in parallel 'feature_fee_estimation.py', 'wallet_hd.py', @@ -120,6 +120,7 @@ BASE_SCRIPTS = [ 'rpc_misc.py', 'interface_rest.py', 'mempool_spend_coinbase.py', + 'wallet_avoidreuse.py', 'mempool_reorg.py', 'mempool_persist.py', 'wallet_multiwallet.py', @@ -494,7 +495,8 @@ class TestHandler: for job in self.jobs: (name, start_time, proc, testdir, log_out, log_err) = job if int(time.time() - start_time) > self.timeout_duration: - # In travis, timeout individual tests (to stop tests hanging and not providing useful output). + # Timeout individual tests if timeout is specified (to stop + # tests hanging and not providing useful output). proc.send_signal(signal.SIGINT) if proc.poll() is not None: log_out.seek(0), log_err.seek(0) @@ -582,7 +584,7 @@ def check_script_list(*, src_dir, fail_on_warn): if len(missed_tests) != 0: print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests))) if fail_on_warn: - # On travis this warning is an error to prevent merging incomplete commits into master + # On CI this warning is an error to prevent merging incomplete commits into master sys.exit(1) diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py new file mode 100755 index 0000000000..58ad835d39 --- /dev/null +++ b/test/functional/wallet_avoidreuse.py @@ -0,0 +1,241 @@ +#!/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 avoid_reuse and setwalletflag features.""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, + connect_nodes_bi, +) + +# TODO: Copied from wallet_groups.py -- should perhaps move into util.py +def assert_approx(v, vexp, vspan=0.00001): + if v < vexp - vspan: + raise AssertionError("%s < [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan))) + if v > vexp + vspan: + raise AssertionError("%s > [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan))) + +def reset_balance(node, discardaddr): + '''Throw away all owned coins by the node so it gets a balance of 0.''' + balance = node.getbalance(avoid_reuse=False) + if balance > 0.5: + node.sendtoaddress(address=discardaddr, amount=balance, subtractfeefromamount=True, avoid_reuse=False) + +def count_unspent(node): + '''Count the unspent outputs for the given node and return various statistics''' + r = { + "total": { + "count": 0, + "sum": 0, + }, + "reused": { + "count": 0, + "sum": 0, + }, + } + supports_reused = True + for utxo in node.listunspent(minconf=0): + r["total"]["count"] += 1 + r["total"]["sum"] += utxo["amount"] + if supports_reused and "reused" in utxo: + if utxo["reused"]: + r["reused"]["count"] += 1 + r["reused"]["sum"] += utxo["amount"] + else: + supports_reused = False + r["reused"]["supported"] = supports_reused + return r + +def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None, reused_count=None, reused_sum=None): + '''Make assertions about a node's unspent output statistics''' + stats = count_unspent(node) + if total_count is not None: + assert_equal(stats["total"]["count"], total_count) + if total_sum is not None: + assert_approx(stats["total"]["sum"], total_sum, 0.001) + if reused_supported is not None: + assert_equal(stats["reused"]["supported"], reused_supported) + if reused_count is not None: + assert_equal(stats["reused"]["count"], reused_count) + if reused_sum is not None: + assert_approx(stats["reused"]["sum"], reused_sum, 0.001) + +def assert_balances(node, mine): + '''Make assertions about a node's getbalances output''' + got = node.getbalances()["mine"] + for k,v in mine.items(): + assert_approx(got[k], v, 0.001) + +class AvoidReuseTest(BitcoinTestFramework): + + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 2 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + '''Set up initial chain and run tests defined below''' + + self.test_persistence() + self.test_immutable() + + self.nodes[0].generate(110) + self.sync_all() + reset_balance(self.nodes[1], self.nodes[0].getnewaddress()) + self.test_fund_send_fund_senddirty() + reset_balance(self.nodes[1], self.nodes[0].getnewaddress()) + self.test_fund_send_fund_send() + + def test_persistence(self): + '''Test that wallet files persist the avoid_reuse flag.''' + # Configure node 1 to use avoid_reuse + self.nodes[1].setwalletflag('avoid_reuse') + + # Flags should be node1.avoid_reuse=false, node2.avoid_reuse=true + assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False) + assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True) + + # Stop and restart node 1 + self.stop_node(1) + self.start_node(1) + connect_nodes_bi(self.nodes, 0, 1) + + # Flags should still be node1.avoid_reuse=false, node2.avoid_reuse=true + assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False) + assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True) + + # Attempting to set flag to its current state should throw + assert_raises_rpc_error(-8, "Wallet flag is already set to false", self.nodes[0].setwalletflag, 'avoid_reuse', False) + assert_raises_rpc_error(-8, "Wallet flag is already set to true", self.nodes[1].setwalletflag, 'avoid_reuse', True) + + def test_immutable(self): + '''Test immutable wallet flags''' + # Attempt to set the disable_private_keys flag; this should not work + assert_raises_rpc_error(-8, "Wallet flag is immutable", self.nodes[1].setwalletflag, 'disable_private_keys') + + tempwallet = ".wallet_avoidreuse.py_test_immutable_wallet.dat" + + # Create a wallet with disable_private_keys set; this should work + self.nodes[1].createwallet(tempwallet, True) + w = self.nodes[1].get_wallet_rpc(tempwallet) + + # Attempt to unset the disable_private_keys flag; this should not work + assert_raises_rpc_error(-8, "Wallet flag is immutable", w.setwalletflag, 'disable_private_keys', False) + + # Unload temp wallet + self.nodes[1].unloadwallet(tempwallet) + + def test_fund_send_fund_senddirty(self): + ''' + Test the same as test_fund_send_fund_send, except send the 10 BTC with + the avoid_reuse flag set to false. This means the 10 BTC send should succeed, + where it fails in test_fund_send_fund_send. + ''' + + fundaddr = self.nodes[1].getnewaddress() + retaddr = self.nodes[0].getnewaddress() + + self.nodes[0].sendtoaddress(fundaddr, 10) + self.nodes[0].generate(1) + self.sync_all() + + # listunspent should show 1 single, unused 10 btc output + assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0) + # getbalances should show no used, 10 btc trusted + assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10}) + # node 0 should not show a used entry, as it does not enable avoid_reuse + assert("used" not in self.nodes[0].getbalances()["mine"]) + + self.nodes[1].sendtoaddress(retaddr, 5) + self.nodes[0].generate(1) + self.sync_all() + + # listunspent should show 1 single, unused 5 btc output + assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0) + # getbalances should show no used, 5 btc trusted + assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5}) + + self.nodes[0].sendtoaddress(fundaddr, 10) + self.nodes[0].generate(1) + self.sync_all() + + # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10) + assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10) + # getbalances should show 10 used, 5 btc trusted + assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5}) + + self.nodes[1].sendtoaddress(address=retaddr, amount=10, avoid_reuse=False) + + # listunspent should show 1 total outputs (5 btc), unused + assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_count=0) + # getbalances should show no used, 5 btc trusted + assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5}) + + # node 1 should now have about 5 btc left (for both cases) + assert_approx(self.nodes[1].getbalance(), 5, 0.001) + assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5, 0.001) + + def test_fund_send_fund_send(self): + ''' + Test the simple case where [1] generates a new address A, then + [0] sends 10 BTC to A. + [1] spends 5 BTC from A. (leaving roughly 5 BTC useable) + [0] sends 10 BTC to A again. + [1] tries to spend 10 BTC (fails; dirty). + [1] tries to spend 4 BTC (succeeds; change address sufficient) + ''' + + fundaddr = self.nodes[1].getnewaddress() + retaddr = self.nodes[0].getnewaddress() + + self.nodes[0].sendtoaddress(fundaddr, 10) + self.nodes[0].generate(1) + self.sync_all() + + # listunspent should show 1 single, unused 10 btc output + assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0) + # getbalances should show no used, 10 btc trusted + assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10}) + + self.nodes[1].sendtoaddress(retaddr, 5) + self.nodes[0].generate(1) + self.sync_all() + + # listunspent should show 1 single, unused 5 btc output + assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0) + # getbalances should show no used, 5 btc trusted + assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5}) + + self.nodes[0].sendtoaddress(fundaddr, 10) + self.nodes[0].generate(1) + self.sync_all() + + # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10) + assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10) + # getbalances should show 10 used, 5 btc trusted + assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5}) + + # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty) + assert_approx(self.nodes[1].getbalance(), 5, 0.001) + assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001) + + assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10) + + self.nodes[1].sendtoaddress(retaddr, 4) + + # listunspent should show 2 total outputs (1, 10 btc), one unused (1), one reused (10) + assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10) + # getbalances should show 10 used, 1 btc trusted + assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1}) + + # node 1 should now have about 1 btc left (no dirty) and 11 (including dirty) + assert_approx(self.nodes[1].getbalance(), 1, 0.001) + assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001) + +if __name__ == '__main__': + AvoidReuseTest().main() diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py index 15f2195e21..137c77a51e 100755 --- a/test/functional/wallet_balance.py +++ b/test/functional/wallet_balance.py @@ -203,6 +203,8 @@ class WalletTest(BitcoinTestFramework): self.log.info('Put txs back into mempool of node 1 (not node 0)') self.nodes[0].invalidateblock(block_reorg) self.nodes[1].invalidateblock(block_reorg) + self.sync_blocks() + self.nodes[0].syncwithvalidationinterfacequeue() assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted self.nodes[0].generatetoaddress(1, ADDRESS_WATCHONLY) assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 568b1f28d8..1fe029a6fb 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -304,7 +304,9 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address): def test_bumpfee_metadata(rbf_node, dest_address): - rbfid = rbf_node.sendtoaddress(dest_address, Decimal("0.00100000"), "comment value", "to value") + assert(rbf_node.getbalance() < 49) + rbf_node.generatetoaddress(101, rbf_node.getnewaddress()) + rbfid = rbf_node.sendtoaddress(dest_address, 49, "comment value", "to value") bumped_tx = rbf_node.bumpfee(rbfid) bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"]) assert_equal(bumped_wtx["comment"], "comment value") @@ -360,7 +362,7 @@ def submit_block_with_tx(node, tx): block.hashMerkleRoot = block.calc_merkle_root() add_witness_commitment(block) block.solve() - node.submitblock(block.serialize(True).hex()) + node.submitblock(block.serialize().hex()) return block def test_no_more_inputs_fails(rbf_node, dest_address): diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py index 7d652a7825..e19c7919a9 100755 --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -571,6 +571,7 @@ class ImportMultiTest(BitcoinTestFramework): # Test ranged descriptor fails if range is not specified xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg" addresses = ["2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1' + addresses += ["bcrt1qrd3n235cj2czsfmsuvqqpr3lu6lg0ju7scl8gn", "bcrt1qfqeppuvj0ww98r6qghmdkj70tv8qpchehegrg8"] # wpkh subscripts corresponding to the above addresses desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))" self.log.info("Ranged descriptor import should fail without a specified range") self.test_importmulti({"desc": descsum_create(desc), @@ -579,17 +580,17 @@ class ImportMultiTest(BitcoinTestFramework): error_code=-8, error_message='Descriptor is ranged, please specify the range') - # Test importing of a ranged descriptor without keys + # Test importing of a ranged descriptor with xpriv self.log.info("Should import the ranged descriptor with specified range as solvable") self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": 1}, - success=True, - warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."]) + success=True) for address in addresses: test_address(self.nodes[1], - key.p2sh_p2wpkh_addr, - solvable=True) + address, + solvable=True, + ismine=True) self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": -1}, success=False, error_code=-8, error_message='End of range is too high') @@ -606,6 +607,23 @@ class ImportMultiTest(BitcoinTestFramework): self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]}, success=False, error_code=-8, error_message='Range is too large') + # Test importing a descriptor containing a WIF private key + wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh" + address = "2MuhcG52uHPknxDgmGPsV18jSHFBnnRgjPg" + desc = "sh(wpkh(" + wif_priv + "))" + self.log.info("Should import a descriptor with a WIF private key as spendable") + self.test_importmulti({"desc": descsum_create(desc), + "timestamp": "now"}, + success=True) + test_address(self.nodes[1], + address, + solvable=True, + ismine=True) + + # dump the private key to ensure it matches what was imported + privkey = self.nodes[1].dumpprivkey(address) + assert_equal(privkey, wif_priv) + # Test importing of a P2PKH address via descriptor key = get_key(self.nodes[0]) self.log.info("Should import a p2pkh address from descriptor") diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 1869f71753..f19cf924d2 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -106,8 +106,10 @@ def run_once(*, corpus, test_list, build_dir, export_coverage): os.path.join(corpus, t), ] logging.debug('Run {} with args {}'.format(t, args)) - output = subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr + result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True) + output = result.stderr logging.debug('Output: {}'.format(output)) + result.check_returncode() if not export_coverage: continue for l in output.splitlines(): diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 2701015c79..70cc16337e 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -30,6 +30,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "policy/fees -> txmempool -> validation -> policy/fees" "qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil" "txmempool -> validation -> validationinterface -> txmempool" + "wallet/ismine -> wallet/wallet -> wallet/ismine" ) EXIT_CODE=0 diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh index c994ae3f4d..cb630c78ad 100755 --- a/test/lint/lint-format-strings.sh +++ b/test/lint/lint-format-strings.sh @@ -13,6 +13,7 @@ export LC_ALL=C FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=( "FatalError,0" "fprintf,1" + "tfm::format,1" # Assuming tfm::::format(std::ostream&, ... "LogConnectFailure,1" "LogPrint,1" "LogPrintf,0" diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index 2b6c78c2c8..9a1aa766f7 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -8,7 +8,6 @@ KNOWN_VIOLATIONS=( "src/dbwrapper.cpp:.*vsnprintf" "src/httprpc.cpp.*trim" "src/init.cpp:.*atoi" - "src/init.cpp:.*fprintf" "src/qt/rpcconsole.cpp:.*atoi" "src/rest.cpp:.*strtol" "src/test/dbwrapper_tests.cpp:.*snprintf" @@ -85,7 +84,7 @@ LOCALE_DEPENDENT_FUNCTIONS=( mbtowc # LC_CTYPE mktime normalize # boost::locale::normalize -# printf # LC_NUMERIC + printf # LC_NUMERIC putwc putwchar scanf # LC_NUMERIC @@ -189,8 +188,7 @@ GIT_GREP_OUTPUT=$(git grep -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FU EXIT_CODE=0 for LOCALE_DEPENDENT_FUNCTION in "${LOCALE_DEPENDENT_FUNCTIONS[@]}"; do MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \ - grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}" | \ - grep -vE 'fprintf\(.*(stdout|stderr)') + grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}") if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != "" ]]; then MATCHES=$(grep -vE "${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES}" <<< "${MATCHES}") fi diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt index f0415443db..a25de2435b 100644 --- a/test/lint/lint-spelling.ignore-words.txt +++ b/test/lint/lint-spelling.ignore-words.txt @@ -5,3 +5,10 @@ mut objext unselect useable +wit +unparseable +copyable +cachable +errorstring +keyserver +homogenous diff --git a/test/sanitizer_suppressions/lsan b/test/sanitizer_suppressions/lsan index 6f15c0f1d4..90a92a5115 100644 --- a/test/sanitizer_suppressions/lsan +++ b/test/sanitizer_suppressions/lsan @@ -4,3 +4,6 @@ leak:libqminimal leak:libQt5Core leak:libQt5Gui leak:libQt5Widgets + +# false-positive due to use of secure_allocator<> +leak:GetRNGState |