aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/data/invalid_txs.py56
-rwxr-xr-xtest/functional/feature_block.py2
-rwxr-xr-xtest/functional/feature_segwit.py2
-rwxr-xr-xtest/functional/mempool_accept.py2
-rwxr-xr-xtest/functional/p2p_invalid_block.py44
-rwxr-xr-xtest/functional/rpc_psbt.py10
-rwxr-xr-xtest/functional/rpc_rawtransaction.py32
-rwxr-xr-xtest/functional/wallet_basic.py2
8 files changed, 134 insertions, 16 deletions
diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py
index 454eb583f7..9dc06422c4 100644
--- a/test/functional/data/invalid_txs.py
+++ b/test/functional/data/invalid_txs.py
@@ -24,7 +24,24 @@ import abc
from test_framework.messages import CTransaction, CTxIn, CTxOut, COutPoint
from test_framework import script as sc
from test_framework.blocktools import create_tx_with_script, MAX_BLOCK_SIGOPS
-
+from test_framework.script import (
+ CScript,
+ OP_CAT,
+ OP_SUBSTR,
+ OP_LEFT,
+ OP_RIGHT,
+ OP_INVERT,
+ OP_AND,
+ OP_OR,
+ OP_XOR,
+ OP_2MUL,
+ OP_2DIV,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_LSHIFT,
+ OP_RSHIFT
+)
basic_p2sh = sc.CScript([sc.OP_HASH160, sc.hash160(sc.CScript([sc.OP_0])), sc.OP_EQUAL])
@@ -178,7 +195,44 @@ class TooManySigops(BadTxTemplate):
script_pub_key=lotsa_checksigs,
amount=1)
+def getDisabledOpcodeTemplate(opcode):
+ """ Creates disabled opcode tx template class"""
+ def get_tx(self):
+ tx = CTransaction()
+ vin = self.valid_txin
+ vin.scriptSig = CScript([opcode])
+ tx.vin.append(vin)
+ tx.vout.append(CTxOut(1, basic_p2sh))
+ tx.calc_sha256()
+ return tx
+
+ return type('DisabledOpcode_' + str(opcode), (BadTxTemplate,), {
+ 'reject_reason': "disabled opcode",
+ 'expect_disconnect': True,
+ 'get_tx': get_tx,
+ 'valid_in_block' : True
+ })
+
+# Disabled opcode tx templates (CVE-2010-5137)
+DisabledOpcodeTemplates = [getDisabledOpcodeTemplate(opcode) for opcode in [
+ OP_CAT,
+ OP_SUBSTR,
+ OP_LEFT,
+ OP_RIGHT,
+ OP_INVERT,
+ OP_AND,
+ OP_OR,
+ OP_XOR,
+ OP_2MUL,
+ OP_2DIV,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_LSHIFT,
+ OP_RSHIFT]]
+
def iter_all_templates():
"""Iterate through all bad transaction template types."""
return BadTxTemplate.__subclasses__()
+
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 377e6c82cd..c74270febc 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -806,7 +806,7 @@ class FullBlockTest(BitcoinTestFramework):
#
# Blocks are not allowed to contain a transaction whose id matches that of an earlier,
# not-fully-spent transaction in the same chain. To test, make identical coinbases;
- # the second one should be rejected.
+ # the second one should be rejected. See also CVE-2012-1909.
#
self.log.info("Reject a block with a transaction with a duplicate hash of a previous transaction (BIP30)")
self.move_tip(60)
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index b9db618575..d2826dd1b7 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -257,7 +257,7 @@ class SegWitTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
tx.vout.append(CTxOut(int(49.95 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))) # Huge fee
tx.calc_sha256()
- txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))
+ txid3 = self.nodes[0].sendrawtransaction(ToHex(tx), 0)
assert tx.wit.is_null()
assert txid3 in self.nodes[0].getrawmempool()
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 209a222004..dee7a04516 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -183,6 +183,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': True}],
rawtxs=[tx.serialize().hex()],
+ maxfeerate=0,
)
self.log.info('A transaction with no outputs')
@@ -211,6 +212,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[tx.serialize().hex()],
)
+ # The following two validations prevent overflow of the output amounts (see CVE-2010-5139).
self.log.info('A transaction with too large output value')
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].nValue = 21000000 * COIN + 1
diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py
index 1e0b876593..905534b862 100755
--- a/test/functional/p2p_invalid_block.py
+++ b/test/functional/p2p_invalid_block.py
@@ -53,10 +53,11 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
block_time = best_block["time"] + 1
# Use merkle-root malleability to generate an invalid block with
- # same blockheader.
+ # same blockheader (CVE-2012-2459).
# Manufacture a block with 3 transactions (coinbase, spend of prior
# coinbase, spend of that spend). Duplicate the 3rd transaction to
# leave merkle root and blockheader unchanged but invalidate the block.
+ # For more information on merkle-root malleability see src/consensus/merkle.cpp.
self.log.info("Test merkle root malleability.")
block2 = create_block(tip, create_coinbase(height), block_time)
@@ -81,15 +82,16 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
node.p2p.send_blocks_and_test([block2], node, success=False, reject_reason='bad-txns-duplicate')
- # Check transactions for duplicate inputs
+ # Check transactions for duplicate inputs (CVE-2018-17144)
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, reject_reason='bad-txns-inputs-duplicate')
+ block2_dup = copy.deepcopy(block2_orig)
+ block2_dup.vtx[2].vin.append(block2_dup.vtx[2].vin[0])
+ block2_dup.vtx[2].rehash()
+ block2_dup.hashMerkleRoot = block2_dup.calc_merkle_root()
+ block2_dup.rehash()
+ block2_dup.solve()
+ node.p2p.send_blocks_and_test([block2_dup], node, success=False, reject_reason='bad-txns-inputs-duplicate')
self.log.info("Test very broken block.")
@@ -105,5 +107,31 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
node.p2p.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount')
+ # Complete testing of CVE-2012-2459 by sending the original block.
+ # It should be accepted even though it has the same hash as the mutated one.
+
+ self.log.info("Test accepting original block after rejecting its mutated version.")
+ node.p2p.send_blocks_and_test([block2_orig], node, success=True, timeout=5)
+
+ # Update tip info
+ height += 1
+ block_time += 1
+ tip = int(block2_orig.hash, 16)
+
+ # Complete testing of CVE-2018-17144, by checking for the inflation bug.
+ # Create a block that spends the output of a tx in a previous block.
+ block4 = create_block(tip, create_coinbase(height), block_time)
+ tx3 = create_tx_with_script(tx2, 0, script_sig=b'\x51', amount=50 * COIN)
+
+ # Duplicates input
+ tx3.vin.append(tx3.vin[0])
+ tx3.rehash()
+ block4.vtx.append(tx3)
+ block4.hashMerkleRoot = block4.calc_merkle_root()
+ block4.rehash()
+ block4.solve()
+ self.log.info("Test inflation by duplicating input")
+ node.p2p.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate')
+
if __name__ == '__main__':
InvalidBlockRequestTest().main()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 5a04e0c8d8..cb8320a6c2 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -382,6 +382,16 @@ class PSBTTest(BitcoinTestFramework):
joined_decoded = self.nodes[0].decodepsbt(joined)
assert len(joined_decoded['inputs']) == 4 and len(joined_decoded['outputs']) == 2 and "final_scriptwitness" not in joined_decoded['inputs'][3] and "final_scriptSig" not in joined_decoded['inputs'][3]
+ # Check that joining shuffles the inputs and outputs
+ # 10 attempts should be enough to get a shuffled join
+ shuffled = False
+ for i in range(0, 10):
+ shuffled_joined = self.nodes[0].joinpsbts([psbt, psbt2])
+ shuffled |= joined != shuffled_joined
+ if shuffled:
+ break
+ assert shuffled
+
# Newly created PSBT needs UTXOs and updating
addr = self.nodes[1].getnewaddress("", "p2sh-segwit")
txid = self.nodes[0].sendtoaddress(addr, 7)
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 4338675270..d1ce97efff 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -432,17 +432,18 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')
+ # Test a transaction with small fee
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
rawTx = self.nodes[0].getrawtransaction(txId, True)
vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000'))
self.sync_all()
inputs = [{ "txid" : txId, "vout" : vout['n'] }]
- outputs = { self.nodes[0].getnewaddress() : Decimal("0.99999000") } # 1000 sat fee
+ outputs = { self.nodes[0].getnewaddress() : Decimal("0.999990000") } # 10000 sat fee
rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
assert_equal(rawTxSigned['complete'], True)
- # 1000 sat fee, ~100 b transaction, fee rate should land around 10 sat/b = 0.00010000 BTC/kB
+ # 10000 sat fee, ~100 b transaction, fee rate should land around 100 sat/b = 0.00100000 BTC/kB
# Thus, testmempoolaccept should reject
testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
assert_equal(testres['allowed'], False)
@@ -450,9 +451,32 @@ class RawTransactionsTest(BitcoinTestFramework):
# and sendrawtransaction should throw
assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
# And below calls should both succeed
- testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate='0.00070000')[0]
+ testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']])[0]
assert_equal(testres['allowed'], True)
- self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate='0.00070000')
+ self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'])
+
+ # Test a transaction with large fee
+ txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
+ rawTx = self.nodes[0].getrawtransaction(txId, True)
+ vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000'))
+
+ self.sync_all()
+ inputs = [{ "txid" : txId, "vout" : vout['n'] }]
+ outputs = { self.nodes[0].getnewaddress() : Decimal("0.98000000") } # 2000000 sat fee
+ rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
+ rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
+ assert_equal(rawTxSigned['complete'], True)
+ # 2000000 sat fee, ~100 b transaction, fee rate should land around 20000 sat/b = 0.20000000 BTC/kB
+ # Thus, testmempoolaccept should reject
+ testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
+ assert_equal(testres['allowed'], False)
+ assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
+ # and sendrawtransaction should throw
+ assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
+ # And below calls should both succeed
+ testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate='0.20000000')[0]
+ assert_equal(testres['allowed'], True)
+ self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate='0.20000000')
if __name__ == '__main__':
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index ce04110240..2283bff2e6 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -433,7 +433,7 @@ class WalletTest(BitcoinTestFramework):
# Split into two chains
rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')})
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
- singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"])
+ singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"], 0)
self.nodes[0].generate(1)
# Make a long chain of unconfirmed payments without hitting mempool limit