diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/README.md | 3 | ||||
-rwxr-xr-x | test/functional/feature_abortnode.py | 4 | ||||
-rwxr-xr-x | test/functional/feature_block.py | 20 | ||||
-rwxr-xr-x | test/functional/feature_dersig.py | 3 | ||||
-rwxr-xr-x | test/functional/framework_test_script.py | 44 | ||||
-rwxr-xr-x | test/functional/mempool_reorg.py | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | test/functional/rpc_estimatefee.py | 0 | ||||
-rw-r--r-- | test/functional/test_framework/bignum.py | 58 | ||||
-rw-r--r-- | test/functional/test_framework/script.py | 285 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 18 | ||||
-rwxr-xr-x | test/functional/wallet_bumpfee.py | 64 | ||||
-rwxr-xr-x | test/functional/wallet_bumpfee_totalfee_deprecation.py | 54 | ||||
-rwxr-xr-x | test/functional/wallet_groups.py | 6 | ||||
-rwxr-xr-x | test/functional/wallet_multiwallet.py | 1 | ||||
-rwxr-xr-x | test/functional/wallet_resendwallettransactions.py | 4 | ||||
-rwxr-xr-x | test/fuzz/test_runner.py | 48 | ||||
-rwxr-xr-x | test/lint/lint-locale-dependence.sh | 16 | ||||
-rw-r--r-- | test/util/data/bitcoin-util-test.json | 40 | ||||
-rw-r--r-- | test/util/data/txcreatescript5.hex | 1 | ||||
-rw-r--r-- | test/util/data/txcreatescript6.hex | 1 |
20 files changed, 333 insertions, 342 deletions
diff --git a/test/functional/README.md b/test/functional/README.md index 6582c1cbcd..004e0afb1d 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -134,9 +134,6 @@ Utilities for manipulating transaction scripts (originally from python-bitcoinli #### [key.py](test_framework/key.py) Test-only secp256k1 elliptic curve implementation -#### [bignum.py](test_framework/bignum.py) -Helpers for script.py - #### [blocktools.py](test_framework/blocktools.py) Helper functions for creating blocks and transactions. diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py index 9b878e8bf8..e47e709431 100755 --- a/test/functional/feature_abortnode.py +++ b/test/functional/feature_abortnode.py @@ -14,11 +14,12 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import wait_until, get_datadir_path, connect_nodes import os -class AbortNodeTest(BitcoinTestFramework): +class AbortNodeTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 + self.rpc_timeout = 240 def setup_network(self): self.setup_nodes() @@ -44,5 +45,6 @@ class AbortNodeTest(BitcoinTestFramework): self.log.info("Node crashed - now verifying restart fails") self.nodes[0].assert_start_raises_init_error() + if __name__ == '__main__': AbortNodeTest().main() diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 38bf2faf89..0c591de869 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -630,17 +630,19 @@ class FullBlockTest(BitcoinTestFramework): self.log.info("Reject a block with invalid work") self.move_tip(44) - b47 = self.next_block(47, solve=False) + b47 = self.next_block(47) target = uint256_from_compact(b47.nBits) - while b47.sha256 < target: + while b47.sha256 <= target: + # Rehash nonces until an invalid too-high-hash block is found. b47.nNonce += 1 b47.rehash() self.send_blocks([b47], False, force_send=True, reject_reason='high-hash', reconnect=True) self.log.info("Reject a block with a timestamp >2 hours in the future") self.move_tip(44) - b48 = self.next_block(48, solve=False) + b48 = self.next_block(48) b48.nTime = int(time.time()) + 60 * 60 * 3 + # Header timestamp has changed. Re-solve the block. b48.solve() self.send_blocks([b48], False, force_send=True, reject_reason='time-too-new') @@ -1261,7 +1263,7 @@ class FullBlockTest(BitcoinTestFramework): self.save_spendable_output() spend = self.get_spendable_output() - self.send_blocks(blocks, True, timeout=1920) + self.send_blocks(blocks, True, timeout=2440) chain1_tip = i # now create alt chain of same length @@ -1273,14 +1275,14 @@ class FullBlockTest(BitcoinTestFramework): # extend alt chain to trigger re-org block = self.next_block("alt" + str(chain1_tip + 1), version=4) - self.send_blocks([block], True, timeout=1920) + self.send_blocks([block], True, timeout=2440) # ... and re-org back to the first chain self.move_tip(chain1_tip) block = self.next_block(chain1_tip + 1, version=4) self.send_blocks([block], False, force_send=True) block = self.next_block(chain1_tip + 2, version=4) - self.send_blocks([block], True, timeout=1920) + self.send_blocks([block], True, timeout=2440) self.log.info("Reject a block with an invalid block header version") b_v1 = self.next_block('b_v1', version=1) @@ -1321,7 +1323,7 @@ class FullBlockTest(BitcoinTestFramework): tx.rehash() return tx - def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), solve=True, *, version=1): + def next_block(self, number, spend=None, additional_coinbase_value=0, script=CScript([OP_TRUE]), *, version=1): if self.tip is None: base_block_hash = self.genesis_hash block_time = int(time.time()) + 1 @@ -1343,8 +1345,8 @@ class FullBlockTest(BitcoinTestFramework): self.sign_tx(tx, spend) self.add_transactions_to_block(block, [tx]) block.hashMerkleRoot = block.calc_merkle_root() - if solve: - block.solve() + # Block is created. Find a valid nonce. + block.solve() self.tip = block self.block_heights[block.sha256] = height assert number not in self.blocks diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 9628945a80..38cdf0501e 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -36,7 +36,6 @@ def unDERify(tx): tx.vin[0].scriptSig = CScript(newscript) - class BIP66Test(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 @@ -45,7 +44,7 @@ class BIP66Test(BitcoinTestFramework): '-par=1', # Use only one script thread to get the exact log msg for testing ]] self.setup_clean_chain = True - self.rpc_timeout = 120 + self.rpc_timeout = 240 def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/framework_test_script.py b/test/functional/framework_test_script.py new file mode 100755 index 0000000000..9d916c0022 --- /dev/null +++ b/test/functional/framework_test_script.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Tests for test_framework.script.""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.script import bn2vch +from test_framework.util import assert_equal + +def test_bn2vch(): + assert_equal(bn2vch(0), bytes([])) + assert_equal(bn2vch(1), bytes([0x01])) + assert_equal(bn2vch(-1), bytes([0x81])) + assert_equal(bn2vch(0x7F), bytes([0x7F])) + assert_equal(bn2vch(-0x7F), bytes([0xFF])) + assert_equal(bn2vch(0x80), bytes([0x80, 0x00])) + assert_equal(bn2vch(-0x80), bytes([0x80, 0x80])) + assert_equal(bn2vch(0xFF), bytes([0xFF, 0x00])) + assert_equal(bn2vch(-0xFF), bytes([0xFF, 0x80])) + assert_equal(bn2vch(0x100), bytes([0x00, 0x01])) + assert_equal(bn2vch(-0x100), bytes([0x00, 0x81])) + assert_equal(bn2vch(0x7FFF), bytes([0xFF, 0x7F])) + assert_equal(bn2vch(-0x8000), bytes([0x00, 0x80, 0x80])) + assert_equal(bn2vch(-0x7FFFFF), bytes([0xFF, 0xFF, 0xFF])) + assert_equal(bn2vch(0x80000000), bytes([0x00, 0x00, 0x00, 0x80, 0x00])) + assert_equal(bn2vch(-0x80000000), bytes([0x00, 0x00, 0x00, 0x80, 0x80])) + assert_equal(bn2vch(0xFFFFFFFF), bytes([0xFF, 0xFF, 0xFF, 0xFF, 0x00])) + + assert_equal(bn2vch(123456789), bytes([0x15, 0xCD, 0x5B, 0x07])) + assert_equal(bn2vch(-54321), bytes([0x31, 0xD4, 0x80])) + +class FrameworkTestScript(BitcoinTestFramework): + def setup_network(self): + pass + + def set_test_params(self): + self.num_nodes = 0 + + def run_test(self): + test_bn2vch() + +if __name__ == '__main__': + FrameworkTestScript().main() diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 3b148d5cf0..d797dff134 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -76,7 +76,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw) - self.sync_all(timeout=360) + self.sync_all(timeout=720) assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, timelock_tx_id}) @@ -91,10 +91,11 @@ class MempoolCoinbaseTest(BitcoinTestFramework): for node in self.nodes: node.invalidateblock(new_blocks[0]) - self.sync_all(timeout=360) + self.sync_all(timeout=720) # mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) + if __name__ == '__main__': MempoolCoinbaseTest().main() diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py index 8bdecfc8cd..8bdecfc8cd 100644..100755 --- a/test/functional/rpc_estimatefee.py +++ b/test/functional/rpc_estimatefee.py diff --git a/test/functional/test_framework/bignum.py b/test/functional/test_framework/bignum.py deleted file mode 100644 index db5ccd62c2..0000000000 --- a/test/functional/test_framework/bignum.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -# -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Big number routines. - -This file is copied from python-bitcoinlib. -""" - -import struct - - -# generic big endian MPI format - -def bn_bytes(v, have_ext=False): - ext = 0 - if have_ext: - ext = 1 - return ((v.bit_length()+7)//8) + ext - -def bn2bin(v): - s = bytearray() - i = bn_bytes(v) - while i > 0: - s.append((v >> ((i-1) * 8)) & 0xff) - i -= 1 - return s - -def bn2mpi(v): - have_ext = False - if v.bit_length() > 0: - have_ext = (v.bit_length() & 0x07) == 0 - - neg = False - if v < 0: - neg = True - v = -v - - s = struct.pack(b">I", bn_bytes(v, have_ext)) - ext = bytearray() - if have_ext: - ext.append(0) - v_bin = bn2bin(v) - if neg: - if have_ext: - ext[0] |= 0x80 - else: - v_bin[0] |= 0x80 - return s + ext + v_bin - -# bitcoin-specific little endian format, with implicit size -def mpi2vch(s): - r = s[4:] # strip size - r = r[::-1] # reverse string, converting BE->LE - return r - -def bn2vch(v): - return bytes(mpi2vch(bn2mpi(v))) diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 51aa9057f7..92725dfcf4 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -6,21 +6,35 @@ This file is modified from python-bitcoinlib. """ - -from .messages import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string - import hashlib import struct -from .bignum import bn2vch +from .messages import ( + CTransaction, + CTxOut, + hash256, + ser_string, + ser_uint256, + sha256, + uint256_from_str, +) MAX_SCRIPT_ELEMENT_SIZE = 520 - OPCODE_NAMES = {} def hash160(s): return hashlib.new('ripemd160', sha256(s)).digest() +def bn2vch(v): + """Convert number to bitcoin-specific little endian format.""" + # We need v.bit_length() bits, plus a sign bit for every nonzero number. + n_bits = v.bit_length() + (v != 0) + # The number of bytes for that is: + n_bytes = (n_bits + 7) // 8 + # Convert number to absolute value + sign in top bit. + encoded_v = 0 if v == 0 else abs(v) | ((v < 0) << (n_bytes * 8 - 1)) + # Serialize to bytes + return encoded_v.to_bytes(n_bytes, 'little') _opcode_instances = [] class CScriptOp(int): @@ -31,13 +45,13 @@ class CScriptOp(int): def encode_op_pushdata(d): """Encode a PUSHDATA op, returning bytes""" if len(d) < 0x4c: - return b'' + bytes([len(d)]) + d # OP_PUSHDATA + return b'' + bytes([len(d)]) + d # OP_PUSHDATA elif len(d) <= 0xff: - return b'\x4c' + bytes([len(d)]) + d # OP_PUSHDATA1 + return b'\x4c' + bytes([len(d)]) + d # OP_PUSHDATA1 elif len(d) <= 0xffff: - return b'\x4d' + struct.pack(b'<H', len(d)) + d # OP_PUSHDATA2 + return b'\x4d' + struct.pack(b'<H', len(d)) + d # OP_PUSHDATA2 elif len(d) <= 0xffffffff: - return b'\x4e' + struct.pack(b'<I', len(d)) + d # OP_PUSHDATA4 + return b'\x4e' + struct.pack(b'<I', len(d)) + d # OP_PUSHDATA4 else: raise ValueError("Data too long to encode in a PUSHDATA op") @@ -50,7 +64,7 @@ class CScriptOp(int): if n == 0: return OP_0 else: - return CScriptOp(OP_1 + n-1) + return CScriptOp(OP_1 + n - 1) def decode_op_n(self): """Decode a small integer opcode, returning an integer""" @@ -60,7 +74,7 @@ class CScriptOp(int): if not (self == OP_0 or OP_1 <= self <= OP_16): raise ValueError('op %r is not an OP_N' % self) - return int(self - OP_1+1) + return int(self - OP_1 + 1) def is_small_int(self): """Return true if the op pushes a small integer to the stack""" @@ -87,7 +101,7 @@ class CScriptOp(int): return _opcode_instances[n] # Populate opcode instance table -for n in range(0xff+1): +for n in range(0xff + 1): CScriptOp(n) @@ -100,7 +114,7 @@ OP_PUSHDATA4 = CScriptOp(0x4e) OP_1NEGATE = CScriptOp(0x4f) OP_RESERVED = CScriptOp(0x50) OP_1 = CScriptOp(0x51) -OP_TRUE=OP_1 +OP_TRUE = OP_1 OP_2 = CScriptOp(0x52) OP_3 = CScriptOp(0x53) OP_4 = CScriptOp(0x54) @@ -232,122 +246,122 @@ OP_PUBKEY = CScriptOp(0xfe) OP_INVALIDOPCODE = CScriptOp(0xff) OPCODE_NAMES.update({ - OP_0 : 'OP_0', - OP_PUSHDATA1 : 'OP_PUSHDATA1', - OP_PUSHDATA2 : 'OP_PUSHDATA2', - OP_PUSHDATA4 : 'OP_PUSHDATA4', - OP_1NEGATE : 'OP_1NEGATE', - OP_RESERVED : 'OP_RESERVED', - OP_1 : 'OP_1', - OP_2 : 'OP_2', - OP_3 : 'OP_3', - OP_4 : 'OP_4', - OP_5 : 'OP_5', - OP_6 : 'OP_6', - OP_7 : 'OP_7', - OP_8 : 'OP_8', - OP_9 : 'OP_9', - OP_10 : 'OP_10', - OP_11 : 'OP_11', - OP_12 : 'OP_12', - OP_13 : 'OP_13', - OP_14 : 'OP_14', - OP_15 : 'OP_15', - OP_16 : 'OP_16', - OP_NOP : 'OP_NOP', - OP_VER : 'OP_VER', - OP_IF : 'OP_IF', - OP_NOTIF : 'OP_NOTIF', - OP_VERIF : 'OP_VERIF', - OP_VERNOTIF : 'OP_VERNOTIF', - OP_ELSE : 'OP_ELSE', - OP_ENDIF : 'OP_ENDIF', - OP_VERIFY : 'OP_VERIFY', - OP_RETURN : 'OP_RETURN', - OP_TOALTSTACK : 'OP_TOALTSTACK', - OP_FROMALTSTACK : 'OP_FROMALTSTACK', - OP_2DROP : 'OP_2DROP', - OP_2DUP : 'OP_2DUP', - OP_3DUP : 'OP_3DUP', - OP_2OVER : 'OP_2OVER', - OP_2ROT : 'OP_2ROT', - OP_2SWAP : 'OP_2SWAP', - OP_IFDUP : 'OP_IFDUP', - OP_DEPTH : 'OP_DEPTH', - OP_DROP : 'OP_DROP', - OP_DUP : 'OP_DUP', - OP_NIP : 'OP_NIP', - OP_OVER : 'OP_OVER', - OP_PICK : 'OP_PICK', - OP_ROLL : 'OP_ROLL', - OP_ROT : 'OP_ROT', - OP_SWAP : 'OP_SWAP', - OP_TUCK : 'OP_TUCK', - OP_CAT : 'OP_CAT', - OP_SUBSTR : 'OP_SUBSTR', - OP_LEFT : 'OP_LEFT', - OP_RIGHT : 'OP_RIGHT', - OP_SIZE : 'OP_SIZE', - OP_INVERT : 'OP_INVERT', - OP_AND : 'OP_AND', - OP_OR : 'OP_OR', - OP_XOR : 'OP_XOR', - OP_EQUAL : 'OP_EQUAL', - OP_EQUALVERIFY : 'OP_EQUALVERIFY', - OP_RESERVED1 : 'OP_RESERVED1', - OP_RESERVED2 : 'OP_RESERVED2', - OP_1ADD : 'OP_1ADD', - OP_1SUB : 'OP_1SUB', - OP_2MUL : 'OP_2MUL', - OP_2DIV : 'OP_2DIV', - OP_NEGATE : 'OP_NEGATE', - OP_ABS : 'OP_ABS', - OP_NOT : 'OP_NOT', - OP_0NOTEQUAL : 'OP_0NOTEQUAL', - OP_ADD : 'OP_ADD', - OP_SUB : 'OP_SUB', - OP_MUL : 'OP_MUL', - OP_DIV : 'OP_DIV', - OP_MOD : 'OP_MOD', - OP_LSHIFT : 'OP_LSHIFT', - OP_RSHIFT : 'OP_RSHIFT', - OP_BOOLAND : 'OP_BOOLAND', - OP_BOOLOR : 'OP_BOOLOR', - OP_NUMEQUAL : 'OP_NUMEQUAL', - OP_NUMEQUALVERIFY : 'OP_NUMEQUALVERIFY', - OP_NUMNOTEQUAL : 'OP_NUMNOTEQUAL', - OP_LESSTHAN : 'OP_LESSTHAN', - OP_GREATERTHAN : 'OP_GREATERTHAN', - OP_LESSTHANOREQUAL : 'OP_LESSTHANOREQUAL', - OP_GREATERTHANOREQUAL : 'OP_GREATERTHANOREQUAL', - OP_MIN : 'OP_MIN', - OP_MAX : 'OP_MAX', - OP_WITHIN : 'OP_WITHIN', - OP_RIPEMD160 : 'OP_RIPEMD160', - OP_SHA1 : 'OP_SHA1', - OP_SHA256 : 'OP_SHA256', - OP_HASH160 : 'OP_HASH160', - OP_HASH256 : 'OP_HASH256', - OP_CODESEPARATOR : 'OP_CODESEPARATOR', - OP_CHECKSIG : 'OP_CHECKSIG', - OP_CHECKSIGVERIFY : 'OP_CHECKSIGVERIFY', - OP_CHECKMULTISIG : 'OP_CHECKMULTISIG', - OP_CHECKMULTISIGVERIFY : 'OP_CHECKMULTISIGVERIFY', - OP_NOP1 : 'OP_NOP1', - OP_CHECKLOCKTIMEVERIFY : 'OP_CHECKLOCKTIMEVERIFY', - OP_CHECKSEQUENCEVERIFY : 'OP_CHECKSEQUENCEVERIFY', - OP_NOP4 : 'OP_NOP4', - OP_NOP5 : 'OP_NOP5', - OP_NOP6 : 'OP_NOP6', - OP_NOP7 : 'OP_NOP7', - OP_NOP8 : 'OP_NOP8', - OP_NOP9 : 'OP_NOP9', - OP_NOP10 : 'OP_NOP10', - OP_SMALLINTEGER : 'OP_SMALLINTEGER', - OP_PUBKEYS : 'OP_PUBKEYS', - OP_PUBKEYHASH : 'OP_PUBKEYHASH', - OP_PUBKEY : 'OP_PUBKEY', - OP_INVALIDOPCODE : 'OP_INVALIDOPCODE', + OP_0: 'OP_0', + OP_PUSHDATA1: 'OP_PUSHDATA1', + OP_PUSHDATA2: 'OP_PUSHDATA2', + OP_PUSHDATA4: 'OP_PUSHDATA4', + OP_1NEGATE: 'OP_1NEGATE', + OP_RESERVED: 'OP_RESERVED', + OP_1: 'OP_1', + OP_2: 'OP_2', + OP_3: 'OP_3', + OP_4: 'OP_4', + OP_5: 'OP_5', + OP_6: 'OP_6', + OP_7: 'OP_7', + OP_8: 'OP_8', + OP_9: 'OP_9', + OP_10: 'OP_10', + OP_11: 'OP_11', + OP_12: 'OP_12', + OP_13: 'OP_13', + OP_14: 'OP_14', + OP_15: 'OP_15', + OP_16: 'OP_16', + OP_NOP: 'OP_NOP', + OP_VER: 'OP_VER', + OP_IF: 'OP_IF', + OP_NOTIF: 'OP_NOTIF', + OP_VERIF: 'OP_VERIF', + OP_VERNOTIF: 'OP_VERNOTIF', + OP_ELSE: 'OP_ELSE', + OP_ENDIF: 'OP_ENDIF', + OP_VERIFY: 'OP_VERIFY', + OP_RETURN: 'OP_RETURN', + OP_TOALTSTACK: 'OP_TOALTSTACK', + OP_FROMALTSTACK: 'OP_FROMALTSTACK', + OP_2DROP: 'OP_2DROP', + OP_2DUP: 'OP_2DUP', + OP_3DUP: 'OP_3DUP', + OP_2OVER: 'OP_2OVER', + OP_2ROT: 'OP_2ROT', + OP_2SWAP: 'OP_2SWAP', + OP_IFDUP: 'OP_IFDUP', + OP_DEPTH: 'OP_DEPTH', + OP_DROP: 'OP_DROP', + OP_DUP: 'OP_DUP', + OP_NIP: 'OP_NIP', + OP_OVER: 'OP_OVER', + OP_PICK: 'OP_PICK', + OP_ROLL: 'OP_ROLL', + OP_ROT: 'OP_ROT', + OP_SWAP: 'OP_SWAP', + OP_TUCK: 'OP_TUCK', + OP_CAT: 'OP_CAT', + OP_SUBSTR: 'OP_SUBSTR', + OP_LEFT: 'OP_LEFT', + OP_RIGHT: 'OP_RIGHT', + OP_SIZE: 'OP_SIZE', + OP_INVERT: 'OP_INVERT', + OP_AND: 'OP_AND', + OP_OR: 'OP_OR', + OP_XOR: 'OP_XOR', + OP_EQUAL: 'OP_EQUAL', + OP_EQUALVERIFY: 'OP_EQUALVERIFY', + OP_RESERVED1: 'OP_RESERVED1', + OP_RESERVED2: 'OP_RESERVED2', + OP_1ADD: 'OP_1ADD', + OP_1SUB: 'OP_1SUB', + OP_2MUL: 'OP_2MUL', + OP_2DIV: 'OP_2DIV', + OP_NEGATE: 'OP_NEGATE', + OP_ABS: 'OP_ABS', + OP_NOT: 'OP_NOT', + OP_0NOTEQUAL: 'OP_0NOTEQUAL', + OP_ADD: 'OP_ADD', + OP_SUB: 'OP_SUB', + OP_MUL: 'OP_MUL', + OP_DIV: 'OP_DIV', + OP_MOD: 'OP_MOD', + OP_LSHIFT: 'OP_LSHIFT', + OP_RSHIFT: 'OP_RSHIFT', + OP_BOOLAND: 'OP_BOOLAND', + OP_BOOLOR: 'OP_BOOLOR', + OP_NUMEQUAL: 'OP_NUMEQUAL', + OP_NUMEQUALVERIFY: 'OP_NUMEQUALVERIFY', + OP_NUMNOTEQUAL: 'OP_NUMNOTEQUAL', + OP_LESSTHAN: 'OP_LESSTHAN', + OP_GREATERTHAN: 'OP_GREATERTHAN', + OP_LESSTHANOREQUAL: 'OP_LESSTHANOREQUAL', + OP_GREATERTHANOREQUAL: 'OP_GREATERTHANOREQUAL', + OP_MIN: 'OP_MIN', + OP_MAX: 'OP_MAX', + OP_WITHIN: 'OP_WITHIN', + OP_RIPEMD160: 'OP_RIPEMD160', + OP_SHA1: 'OP_SHA1', + OP_SHA256: 'OP_SHA256', + OP_HASH160: 'OP_HASH160', + OP_HASH256: 'OP_HASH256', + OP_CODESEPARATOR: 'OP_CODESEPARATOR', + OP_CHECKSIG: 'OP_CHECKSIG', + OP_CHECKSIGVERIFY: 'OP_CHECKSIGVERIFY', + OP_CHECKMULTISIG: 'OP_CHECKMULTISIG', + OP_CHECKMULTISIGVERIFY: 'OP_CHECKMULTISIGVERIFY', + OP_NOP1: 'OP_NOP1', + OP_CHECKLOCKTIMEVERIFY: 'OP_CHECKLOCKTIMEVERIFY', + OP_CHECKSEQUENCEVERIFY: 'OP_CHECKSEQUENCEVERIFY', + OP_NOP4: 'OP_NOP4', + OP_NOP5: 'OP_NOP5', + OP_NOP6: 'OP_NOP6', + OP_NOP7: 'OP_NOP7', + OP_NOP8: 'OP_NOP8', + OP_NOP9: 'OP_NOP9', + OP_NOP10: 'OP_NOP10', + OP_SMALLINTEGER: 'OP_SMALLINTEGER', + OP_PUBKEYS: 'OP_PUBKEYS', + OP_PUBKEYHASH: 'OP_PUBKEYHASH', + OP_PUBKEY: 'OP_PUBKEY', + OP_INVALIDOPCODE: 'OP_INVALIDOPCODE', }) class CScriptInvalidError(Exception): @@ -392,10 +406,10 @@ class CScriptNum: if len(value) == 0: return result for i, byte in enumerate(value): - result |= int(byte) << 8*i + result |= int(byte) << 8 * i if value[-1] >= 0x80: # Mask for all but the highest result bit - num_mask = (2**(len(value)*8) - 1) >> 1 + num_mask = (2**(len(value) * 8) - 1) >> 1 result &= num_mask result *= -1 return result @@ -493,21 +507,20 @@ class CScript(bytes): pushdata_type = 'PUSHDATA2' if i + 1 >= len(self): raise CScriptInvalidError('PUSHDATA2: missing data length') - datasize = self[i] + (self[i+1] << 8) + datasize = self[i] + (self[i + 1] << 8) i += 2 elif opcode == OP_PUSHDATA4: pushdata_type = 'PUSHDATA4' if i + 3 >= len(self): raise CScriptInvalidError('PUSHDATA4: missing data length') - datasize = self[i] + (self[i+1] << 8) + (self[i+2] << 16) + (self[i+3] << 24) + datasize = self[i] + (self[i + 1] << 8) + (self[i + 2] << 16) + (self[i + 3] << 24) i += 4 else: - assert False # shouldn't happen - + assert False # shouldn't happen - data = bytes(self[i:i+datasize]) + data = bytes(self[i:i + datasize]) # Check for truncation if len(data) < datasize: diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 9b868020e1..2f307750a9 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -19,9 +19,8 @@ import datetime import os import time import shutil -import signal -import sys import subprocess +import sys import tempfile import re import logging @@ -184,7 +183,6 @@ BASE_SCRIPTS = [ 'rpc_bind.py --nonloopback', 'mining_basic.py', 'wallet_bumpfee.py', - 'wallet_bumpfee_totalfee_deprecation.py', 'wallet_implicitsegwit.py', 'rpc_named_arguments.py', 'wallet_listsinceblock.py', @@ -223,6 +221,7 @@ BASE_SCRIPTS = [ 'rpc_help.py', 'feature_help.py', 'feature_shutdown.py', + 'framework_test_script.py', # Don't append tests at the end to avoid merge conflicts # Put them in a random line within the section that fits their approximate run-time ] @@ -366,11 +365,10 @@ def main(): args=passon_args, combined_logs_len=args.combinedlogslen, failfast=args.failfast, - runs_ci=args.ci, use_term_control=args.ansi, ) -def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, runs_ci, use_term_control): +def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, use_term_control): args = args or [] # Warn if bitcoind is already running @@ -412,7 +410,6 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= tmpdir=tmpdir, test_list=test_list, flags=flags, - timeout_duration=40 * 60 if runs_ci else float('inf'), # in seconds use_term_control=use_term_control, ) start_time = time.time() @@ -497,12 +494,11 @@ class TestHandler: Trigger the test scripts passed in via the list. """ - def __init__(self, *, num_tests_parallel, tests_dir, tmpdir, test_list, flags, timeout_duration, use_term_control): + def __init__(self, *, num_tests_parallel, tests_dir, tmpdir, test_list, flags, use_term_control): assert num_tests_parallel >= 1 self.num_jobs = num_tests_parallel self.tests_dir = tests_dir self.tmpdir = tmpdir - self.timeout_duration = timeout_duration self.test_list = test_list self.flags = flags self.num_running = 0 @@ -543,10 +539,6 @@ class TestHandler: time.sleep(.5) for job in self.jobs: (name, start_time, proc, testdir, log_out, log_err) = job - if int(time.time() - start_time) > self.timeout_duration: - # 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) [stdout, stderr] = [log_file.read().decode('utf-8') for log_file in (log_out, log_err)] @@ -615,7 +607,7 @@ class TestResult(): def check_script_prefixes(): """Check that test scripts start with one of the allowed name prefixes.""" - good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool)_") + good_prefixes_re = re.compile("^(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool|framework_test)_") bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None] if bad_script_names: diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 336e246e33..38c9807757 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -30,6 +30,13 @@ from test_framework.util import ( WALLET_PASSPHRASE = "test" WALLET_PASSPHRASE_TIMEOUT = 3600 +# Fee rates (in BTC per 1000 vbytes) +INSUFFICIENT = 0.00001000 +ECONOMICAL = 0.00050000 +NORMAL = 0.00100000 +HIGH = 0.00500000 +TOO_HIGH = 1.00000000 + class BumpFeeTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 @@ -37,7 +44,6 @@ class BumpFeeTest(BitcoinTestFramework): self.extra_args = [[ "-walletrbf={}".format(i), "-mintxfee=0.00002", - "-deprecatedrpc=totalFee", "-addresstype=bech32", ] for i in range(self.num_nodes)] @@ -75,7 +81,6 @@ class BumpFeeTest(BitcoinTestFramework): test_nonrbf_bumpfee_fails(self, peer_node, dest_address) test_notmine_bumpfee_fails(self, rbf_node, peer_node, dest_address) test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address) - test_small_output_fails(self, rbf_node, dest_address) test_dust_to_fee(self, rbf_node, dest_address) test_settxfee(self, rbf_node, dest_address) test_watchonly_psbt(self, peer_node, rbf_node, dest_address) @@ -93,13 +98,13 @@ class BumpFeeTest(BitcoinTestFramework): def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address): - self.log.info('Test simple bumpfee') + self.log.info('Test simple bumpfee: {}'.format(mode)) rbfid = spend_one_input(rbf_node, dest_address) rbftx = rbf_node.gettransaction(rbfid) self.sync_mempools((rbf_node, peer_node)) assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() if mode == "fee_rate": - bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate":0.0015}) + bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": NORMAL}) else: bumped_tx = rbf_node.bumpfee(rbfid) assert_equal(bumped_tx["errors"], []) @@ -120,21 +125,21 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address): assert_equal(bumpedwtx["replaces_txid"], rbfid) def test_feerate_args(self, rbf_node, peer_node, dest_address): - self.log.info('Test feerate args') + self.log.info('Test fee_rate args') rbfid = spend_one_input(rbf_node, dest_address) self.sync_mempools((rbf_node, peer_node)) assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() - assert_raises_rpc_error(-8, "confTarget can't be set with totalFee or fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.", rbf_node.bumpfee, rbfid, {"fee_rate":0.00001, "confTarget":1}) - assert_raises_rpc_error(-8, "confTarget can't be set with totalFee or fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.", rbf_node.bumpfee, rbfid, {"totalFee":0.00001, "confTarget":1}) - assert_raises_rpc_error(-8, "fee_rate can't be set along with totalFee.", rbf_node.bumpfee, rbfid, {"fee_rate":0.00001, "totalFee":0.001}) + assert_raises_rpc_error(-8, "confTarget can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.", rbf_node.bumpfee, rbfid, {"fee_rate": NORMAL, "confTarget": 1}) + + assert_raises_rpc_error(-3, "Unexpected key totalFee", rbf_node.bumpfee, rbfid, {"totalFee": NORMAL}) # Bumping to just above minrelay should fail to increase total fee enough, at least - assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, rbfid, {"fee_rate":0.00001000}) + assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, rbfid, {"fee_rate": INSUFFICIENT}) assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, {"fee_rate":-1}) - assert_raises_rpc_error(-4, "is too high (cannot be higher than", rbf_node.bumpfee, rbfid, {"fee_rate":1}) + assert_raises_rpc_error(-4, "is too high (cannot be higher than", rbf_node.bumpfee, rbfid, {"fee_rate": TOO_HIGH}) def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address): @@ -204,15 +209,6 @@ def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_ad rbf_node.sendrawtransaction(tx["hex"]) assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) -def test_small_output_fails(self, rbf_node, dest_address): - self.log.info('Test totalFee bump with small output fails') - # cannot bump fee with a too-small output - rbfid = spend_one_input(rbf_node, dest_address) - rbf_node.bumpfee(rbfid, {"totalFee": 50000}) - - rbfid = spend_one_input(rbf_node, dest_address) - assert_raises_rpc_error(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001}) - def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): self.log.info('Testing small output with feerate bump succeeds') @@ -255,15 +251,19 @@ def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): def test_dust_to_fee(self, rbf_node, dest_address): self.log.info('Test that bumped output that is dust is dropped to fee') - # the bumped tx sets fee=49,900, but it converts to 50,000 rbfid = spend_one_input(rbf_node, dest_address) fulltx = rbf_node.getrawtransaction(rbfid, 1) - # (31-vbyte p2wpkh output size + 67-vbyte p2wpkh spend estimate) * 10k(discard_rate) / 1000 = 980 - bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 50000 - 980}) + # size of transaction (p2wpkh, 1 input, 2 outputs): 141 vbytes + assert_equal(fulltx["vsize"], 141) + # bump with fee_rate of 0.00350000 BTC per 1000 vbytes + # expected bump fee of 141 vbytes * fee_rate 0.00350000 BTC / 1000 vbytes = 0.00049350 BTC + # but dust is dropped, so actual bump fee is 0.00050000 + bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": 0.0035}) 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(full_bumped_tx["vout"][0]['value'], Decimal("0.00050000")) def test_settxfee(self, rbf_node, dest_address): @@ -285,7 +285,8 @@ def test_settxfee(self, rbf_node, dest_address): def test_maxtxfee_fails(self, rbf_node, dest_address): self.log.info('Test that bumpfee fails when it hits -matxfee') # size of bumped transaction (p2wpkh, 1 input, 2 outputs): 141 vbytes - # expected bumping feerate of 20 sats/vbyte => 141*20 sats = 0.00002820 btc + # expected bump fee of 141 vbytes * 0.00200000 BTC / 1000 vbytes = 0.00002820 BTC + # which exceeds maxtxfee and is expected to raise self.restart_node(1, ['-maxtxfee=0.000025'] + self.extra_args[1]) rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) rbfid = spend_one_input(rbf_node, dest_address) @@ -356,7 +357,7 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address): assert_equal(len(watcher.decodepsbt(psbt)["tx"]["vin"]), 1) # Bump fee, obnoxiously high to add additional watchonly input - bumped_psbt = watcher.bumpfee(original_txid, {"fee_rate":0.005}) + bumped_psbt = watcher.bumpfee(original_txid, {"fee_rate": HIGH}) assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1) assert "txid" not in bumped_psbt assert_equal(bumped_psbt["origfee"], -watcher.gettransaction(original_txid)["fee"]) @@ -378,17 +379,17 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address): def test_rebumping(self, rbf_node, dest_address): self.log.info('Test that re-bumping the original tx fails, but bumping successor works') rbfid = spend_one_input(rbf_node, dest_address) - bumped = rbf_node.bumpfee(rbfid, {"totalFee": 2000}) - assert_raises_rpc_error(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000}) - rbf_node.bumpfee(bumped["txid"], {"totalFee": 3000}) + bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL}) + assert_raises_rpc_error(-4, "already bumped", rbf_node.bumpfee, rbfid, {"fee_rate": NORMAL}) + rbf_node.bumpfee(bumped["txid"], {"fee_rate": NORMAL}) def test_rebumping_not_replaceable(self, rbf_node, dest_address): self.log.info('Test that re-bumping non-replaceable fails') rbfid = spend_one_input(rbf_node, dest_address) - bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False}) + bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL, "replaceable": False}) assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], - {"totalFee": 20000}) + {"fee_rate": NORMAL}) def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): @@ -450,7 +451,7 @@ def test_locked_wallet_fails(self, rbf_node, dest_address): rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) def test_change_script_match(self, rbf_node, dest_address): - self.log.info('Test that the same change addresses is used for the replacement transaction when possible.') + self.log.info('Test that the same change addresses is used for the replacement transaction when possible') def get_change_address(tx): tx_details = rbf_node.getrawtransaction(tx, 1) @@ -463,7 +464,7 @@ def test_change_script_match(self, rbf_node, dest_address): assert_equal(len(change_addresses), 1) # Now find that address in each subsequent tx, and no other change - bumped_total_tx = rbf_node.bumpfee(rbfid, {"totalFee": 2000}) + bumped_total_tx = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL}) assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'])) bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"]) assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'])) @@ -503,5 +504,6 @@ def test_no_more_inputs_fails(self, rbf_node, dest_address): rbfid = rbf_node.sendtoaddress(rbf_node.getnewaddress(), rbf_node.getbalance(), "", "", True) assert_raises_rpc_error(-4, "Unable to create transaction: Insufficient funds", rbf_node.bumpfee, rbfid) + if __name__ == "__main__": BumpFeeTest().main() diff --git a/test/functional/wallet_bumpfee_totalfee_deprecation.py b/test/functional/wallet_bumpfee_totalfee_deprecation.py deleted file mode 100755 index b8e097c32e..0000000000 --- a/test/functional/wallet_bumpfee_totalfee_deprecation.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2019 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 deprecation of passing `totalFee` to the bumpfee RPC.""" -from decimal import Decimal - -from test_framework.messages import BIP125_SEQUENCE_NUMBER -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_raises_rpc_error - -class BumpFeeWithTotalFeeArgumentDeprecationTest(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 2 - self.extra_args = [[ - "-walletrbf={}".format(i), - "-mintxfee=0.00002", - ] for i in range(self.num_nodes)] - - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - - def run_test(self): - peer_node, rbf_node = self.nodes - peer_node.generate(110) - self.sync_all() - peer_node.sendtoaddress(rbf_node.getnewaddress(), 0.001) - self.sync_all() - peer_node.generate(1) - self.sync_all() - rbfid = spend_one_input(rbf_node, peer_node.getnewaddress()) - - self.log.info("Testing bumpfee with totalFee argument raises RPC error with deprecation message") - assert_raises_rpc_error( - -8, - "totalFee argument has been deprecated and will be removed in 0.20. " + - "Please use -deprecatedrpc=totalFee to continue using this argument until removal.", - rbf_node.bumpfee, rbfid, {"totalFee": 2000}) - - self.log.info("Testing bumpfee without totalFee argument does not raise") - rbf_node.bumpfee(rbfid) - -def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")): - tx_input = dict(sequence=BIP125_SEQUENCE_NUMBER, - **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000"))) - destinations = {dest_address: Decimal("0.00050000")} - destinations[node.getrawchangeaddress()] = change_size - rawtx = node.createrawtransaction([tx_input], destinations) - signedtx = node.signrawtransactionwithwallet(rawtx) - txid = node.sendrawtransaction(signedtx["hex"]) - return txid - -if __name__ == "__main__": - BumpFeeWithTotalFeeArgumentDeprecationTest().main() diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index f2fa1d3e40..261a43472b 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -11,12 +11,13 @@ from test_framework.util import ( assert_equal, ) + class WalletGroupTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [[], [], ['-avoidpartialspends']] - self.rpc_timeout = 240 + self.rpc_timeout = 480 def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -87,5 +88,6 @@ class WalletGroupTest(BitcoinTestFramework): # is way too big. assert self.nodes[2].sendtoaddress(address=addr2[0], amount=5) + if __name__ == '__main__': - WalletGroupTest().main () + WalletGroupTest().main() diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index f2fa41b647..78ead514a5 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -24,6 +24,7 @@ class MultiWalletTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 + self.rpc_timeout = 120 def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index 91d26e9cb3..d122e3db52 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -12,6 +12,7 @@ from test_framework.mininode import P2PInterface, mininode_lock from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, wait_until + class P2PStoreTxInvs(P2PInterface): def __init__(self): super().__init__() @@ -24,6 +25,7 @@ class P2PStoreTxInvs(P2PInterface): # save txid self.tx_invs_received[i.hash] += 1 + class ResendWalletTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 @@ -63,6 +65,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): node.submitblock(ToHex(block)) # Transaction should not be rebroadcast + node.syncwithvalidationinterfacequeue() node.p2ps[1].sync_with_ping() assert_equal(node.p2ps[1].tx_invs_received[txid], 0) @@ -72,5 +75,6 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): node.setmocktime(rebroadcast_time) wait_until(lambda: node.p2ps[1].tx_invs_received[txid] >= 1, lock=mininode_lock) + if __name__ == '__main__': ResendWalletTransactionsTest().main() diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index 520a2b5a95..1786c39c36 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -14,7 +14,10 @@ import logging def main(): - parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description='''Run the fuzz targets with all inputs from the seed_dir once.''', + ) parser.add_argument( "-l", "--loglevel", @@ -23,11 +26,6 @@ def main(): help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console.", ) parser.add_argument( - '--export_coverage', - action='store_true', - help='If true, export coverage information to files in the seed corpus', - ) - parser.add_argument( '--valgrind', action='store_true', help='If true, run fuzzing binaries under the valgrind memory error detector', @@ -46,6 +44,10 @@ def main(): nargs='*', help='The target(s) to run. Default is to run all targets.', ) + parser.add_argument( + '--m_dir', + help='Merge inputs from this directory into the seed_dir. Needs /target subdirectory.', + ) args = parser.parse_args() @@ -122,16 +124,39 @@ def main(): logging.error("subprocess timed out: Currently only libFuzzer is supported") sys.exit(1) + if args.m_dir: + merge_inputs( + corpus=args.seed_dir, + test_list=test_list_selection, + build_dir=config["environment"]["BUILDDIR"], + merge_dir=args.m_dir, + ) + run_once( corpus=args.seed_dir, test_list=test_list_selection, build_dir=config["environment"]["BUILDDIR"], - export_coverage=args.export_coverage, use_valgrind=args.valgrind, ) -def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind): +def merge_inputs(*, corpus, test_list, build_dir, merge_dir): + logging.info("Merge the inputs in the passed dir into the seed_dir. Passed dir {}".format(merge_dir)) + for t in test_list: + args = [ + os.path.join(build_dir, 'src', 'test', 'fuzz', t), + '-merge=1', + os.path.join(corpus, t), + os.path.join(merge_dir, t), + ] + os.makedirs(os.path.join(corpus, t), exist_ok=True) + os.makedirs(os.path.join(merge_dir, t), exist_ok=True) + logging.debug('Run {} with args {}'.format(t, args)) + output = subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr + logging.debug('Output: {}'.format(output)) + + +def run_once(*, corpus, test_list, build_dir, use_valgrind): for t in test_list: corpus_path = os.path.join(corpus, t) os.makedirs(corpus_path, exist_ok=True) @@ -155,13 +180,6 @@ def run_once(*, corpus, test_list, build_dir, export_coverage, use_valgrind): logging.info(e.stderr) logging.info("Target \"{}\" failed with exit code {}: {}".format(t, e.returncode, " ".join(args))) sys.exit(1) - if not export_coverage: - continue - for l in output.splitlines(): - if 'INITED' in l: - with open(os.path.join(corpus, t + '_coverage'), 'w', encoding='utf-8') as cov_file: - cov_file.write(l) - break def parse_test_list(makefile): diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index 0cb38b6fdb..70410d7405 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -6,31 +6,16 @@ export LC_ALL=C KNOWN_VIOLATIONS=( "src/bitcoin-tx.cpp.*stoul" - "src/bitcoin-tx.cpp.*std::to_string" "src/bitcoin-tx.cpp.*trim_right" "src/dbwrapper.cpp.*stoul" "src/dbwrapper.cpp:.*vsnprintf" "src/httprpc.cpp.*trim" "src/init.cpp:.*atoi" - "src/qt/optionsmodel.cpp.*std::to_string" "src/qt/rpcconsole.cpp:.*atoi" "src/rest.cpp:.*strtol" - "src/rpc/net.cpp.*std::to_string" - "src/rpc/rawtransaction.cpp.*std::to_string" - "src/rpc/util.cpp.*std::to_string" - "src/test/addrman_tests.cpp.*std::to_string" - "src/test/blockchain_tests.cpp.*std::to_string" "src/test/dbwrapper_tests.cpp:.*snprintf" - "src/test/denialofservice_tests.cpp.*std::to_string" "src/test/fuzz/locale.cpp" "src/test/fuzz/parse_numbers.cpp:.*atoi" - "src/test/key_tests.cpp.*std::to_string" - "src/test/net_tests.cpp.*std::to_string" - "src/test/settings_tests.cpp.*std::to_string" - "src/test/timedata_tests.cpp.*std::to_string" - "src/test/util/setup_common.cpp.*std::to_string" - "src/test/util_tests.cpp.*std::to_string" - "src/test/util_threadnames_tests.cpp.*std::to_string" "src/torcontrol.cpp:.*atoi" "src/torcontrol.cpp:.*strtol" "src/util/strencodings.cpp:.*atoi" @@ -38,7 +23,6 @@ KNOWN_VIOLATIONS=( "src/util/strencodings.cpp:.*strtoul" "src/util/strencodings.h:.*atoi" "src/util/system.cpp:.*atoi" - "src/wallet/scriptpubkeyman.cpp.*std::to_string" ) REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/)" diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index 761923a818..99cd4ab695 100644 --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -219,6 +219,12 @@ "description": "Parses a transaction with no inputs and a single output script (output in json)" }, { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:123badscript"], + "return_code": 1, + "error_txt": "error: script parse error", + "description": "Create a new transaction with an invalid output script" + }, + { "exec": "./bitcoin-tx", "args": ["-create", "outscript=0:OP_DROP", "nversion=1"], "output_cmp": "txcreatescript1.hex", "description": "Create a new transaction with a single output script (OP_DROP)" @@ -259,6 +265,40 @@ "description": "Create a new transaction with a single output script (OP_DROP) in a P2SH, wrapped in a P2SH (output as json)" }, { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:9999999999"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number above the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:4294967296"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number just above the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:4294967295"], + "output_cmp": "txcreatescript5.hex", + "description": "Try to parse an output script with a decimal number at the upper limit of the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:-9999999999"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number below the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:-4294967296"], + "return_code": 1, + "error_txt": "error: script parse error: decimal numeric value only allowed in the range -0xFFFFFFFF...0xFFFFFFFF", + "description": "Try to parse an output script with a decimal number just below the allowed range" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:-4294967295"], + "output_cmp": "txcreatescript6.hex", + "description": "Try to parse an output script with a decimal number at the lower limit of the allowed range" + }, + { "exec": "./bitcoin-tx", "args": ["-create", "nversion=1", "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", diff --git a/test/util/data/txcreatescript5.hex b/test/util/data/txcreatescript5.hex new file mode 100644 index 0000000000..48e0a12b0c --- /dev/null +++ b/test/util/data/txcreatescript5.hex @@ -0,0 +1 @@ +02000000000100000000000000000605ffffffff0000000000 diff --git a/test/util/data/txcreatescript6.hex b/test/util/data/txcreatescript6.hex new file mode 100644 index 0000000000..b98293813d --- /dev/null +++ b/test/util/data/txcreatescript6.hex @@ -0,0 +1 @@ +02000000000100000000000000000605ffffffff8000000000 |