rpc_rawtransaction.py raw
1 #!/usr/bin/env python3
2 # Copyright (c) 2014-present The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """Test the rawtransaction RPCs.
6
7 Test the following RPCs:
8 - getrawtransaction
9 - createrawtransaction
10 - signrawtransactionwithwallet
11 - sendrawtransaction
12 - decoderawtransaction
13 """
14
15 from collections import OrderedDict
16 from decimal import Decimal
17 from itertools import product
18
19 from test_framework.messages import (
20 MAX_BIP125_RBF_SEQUENCE,
21 COIN,
22 TX_MAX_STANDARD_VERSION,
23 TX_MIN_STANDARD_VERSION,
24 CTransaction,
25 CTxOut,
26 tx_from_hex,
27 )
28 from test_framework.script import (
29 CScript,
30 OP_FALSE,
31 OP_INVALIDOPCODE,
32 OP_RETURN,
33 )
34 from test_framework.test_framework import BitcoinTestFramework
35 from test_framework.util import (
36 assert_equal,
37 assert_greater_than,
38 assert_raises_rpc_error,
39 sync_txindex,
40 )
41 from test_framework.wallet import (
42 getnewdestination,
43 MiniWallet,
44 )
45
46
47 TXID = "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000"
48
49
50 class multidict(dict):
51 """Dictionary that allows duplicate keys.
52
53 Constructed with a list of (key, value) tuples. When dumped by the json module,
54 will output invalid json with repeated keys, eg:
55 >>> json.dumps(multidict([(1,2),(1,2)])
56 '{"1": 2, "1": 2}'
57
58 Used to test calls to rpc methods with repeated keys in the json object."""
59
60 def __init__(self, x):
61 dict.__init__(self, x)
62 self.x = x
63
64 def items(self):
65 return self.x
66
67
68 class RawTransactionsTest(BitcoinTestFramework):
69 def set_test_params(self):
70 self.num_nodes = 3
71 self.extra_args = [
72 ["-txindex"],
73 [],
74 ["-fastprune", "-prune=1"],
75 ]
76 # whitelist peers to speed up tx relay / mempool sync
77 self.noban_tx_relay = True
78 self.supports_cli = False
79
80 def setup_network(self):
81 super().setup_network()
82 self.connect_nodes(0, 2)
83
84 def run_test(self):
85 self.wallet = MiniWallet(self.nodes[0])
86
87 self.getrawtransaction_tests()
88 self.createrawtransaction_tests()
89 self.sendrawtransaction_tests()
90 self.sendrawtransaction_testmempoolaccept_tests()
91 self.decoderawtransaction_tests()
92 self.transaction_version_number_tests()
93 self.getrawtransaction_verbosity_tests()
94
95 def getrawtransaction_tests(self):
96 tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
97 self.generate(self.nodes[0], 1)
98 txId = tx['txid']
99 err_msg = (
100 "No such mempool transaction. Use -txindex or provide a block hash to enable"
101 " blockchain transaction queries. Use gettransaction for wallet transactions."
102 )
103
104 for n in [0, 2]:
105 self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex")
106
107 if n == 0:
108 sync_txindex(self, self.nodes[n])
109 # With -txindex.
110 # 1. valid parameters - only supply txid
111 assert_equal(self.nodes[n].getrawtransaction(txId), tx['hex'])
112
113 # 2. valid parameters - supply txid and 0 for non-verbose
114 assert_equal(self.nodes[n].getrawtransaction(txId, 0), tx['hex'])
115
116 # 3. valid parameters - supply txid and False for non-verbose
117 assert_equal(self.nodes[n].getrawtransaction(txId, False), tx['hex'])
118
119 # 4. valid parameters - supply txid and 1 for verbose.
120 # We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
121 assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], tx['hex'])
122 assert_equal(self.nodes[n].getrawtransaction(txId, 2)["hex"], tx['hex'])
123
124 # 5. valid parameters - supply txid and True for non-verbose
125 assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], tx['hex'])
126 else:
127 # Without -txindex, expect to raise.
128 for verbose in [None, 0, False, 1, True]:
129 assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txId, verbose)
130
131 # 6. invalid parameters - supply txid and invalid boolean values (strings) for verbose
132 for value in ["True", "False"]:
133 assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbose=value)
134 assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txid=txId, verbosity=value)
135
136 # 7. invalid parameters - supply txid and empty array
137 assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, [])
138
139 # 8. invalid parameters - supply txid and empty dict
140 assert_raises_rpc_error(-3, "not of expected type number", self.nodes[n].getrawtransaction, txId, {})
141
142 # Make a tx by sending, then generate 2 blocks; block1 has the tx in it
143 tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']
144 block1, block2 = self.generate(self.nodes[2], 2)
145 for n in [0, 2]:
146 self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex, with blockhash")
147 # We should be able to get the raw transaction by providing the correct block
148 gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True, blockhash=block1)
149 assert_equal(gottx['txid'], tx)
150 assert_equal(gottx['in_active_chain'], True)
151 if n == 0:
152 self.log.info("Test getrawtransaction with -txindex, without blockhash: 'in_active_chain' should be absent")
153 for v in [1,2]:
154 gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v)
155 assert_equal(gottx['txid'], tx)
156 assert 'in_active_chain' not in gottx
157 else:
158 self.log.info("Test getrawtransaction without -txindex, without blockhash: expect the call to raise")
159 assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txid=tx, verbose=True)
160 # We should not get the tx if we provide an unrelated block
161 assert_raises_rpc_error(-5, "No such transaction found", self.nodes[n].getrawtransaction, txid=tx, blockhash=block2)
162 # An invalid block hash should raise the correct errors
163 assert_raises_rpc_error(-3, "JSON value of type bool is not of expected type string", self.nodes[n].getrawtransaction, txid=tx, blockhash=True)
164 assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 6, for 'foobar')", self.nodes[n].getrawtransaction, txid=tx, blockhash="foobar")
165 assert_raises_rpc_error(-8, "parameter 3 must be of length 64 (not 8, for 'abcd1234')", self.nodes[n].getrawtransaction, txid=tx, blockhash="abcd1234")
166 foo = "ZZZ0000000000000000000000000000000000000000000000000000000000000"
167 assert_raises_rpc_error(-8, f"parameter 3 must be hexadecimal string (not '{foo}')", self.nodes[n].getrawtransaction, txid=tx, blockhash=foo)
168 bar = "0000000000000000000000000000000000000000000000000000000000000000"
169 assert_raises_rpc_error(-5, "Block hash not found", self.nodes[n].getrawtransaction, txid=tx, blockhash=bar)
170 # Undo the blocks and verify that "in_active_chain" is false.
171 self.nodes[n].invalidateblock(block1)
172 gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True, blockhash=block1)
173 assert_equal(gottx['in_active_chain'], False)
174 self.nodes[n].reconsiderblock(block1)
175 assert_equal(self.nodes[n].getbestblockhash(), block2)
176
177 self.log.info("Test getrawtransaction on genesis block coinbase returns an error")
178 block = self.nodes[0].getblock(self.nodes[0].getblockhash(0))
179 assert_raises_rpc_error(-5, "The genesis block coinbase is not considered an ordinary transaction", self.nodes[0].getrawtransaction, block['merkleroot'])
180
181 def getrawtransaction_verbosity_tests(self):
182 tx = self.wallet.send_self_transfer(from_node=self.nodes[1])['txid']
183 [block1] = self.generate(self.nodes[1], 1)
184 fields = [
185 'blockhash',
186 'blocktime',
187 'confirmations',
188 'hash',
189 'hex',
190 'in_active_chain',
191 'locktime',
192 'size',
193 'time',
194 'txid',
195 'vin',
196 'vout',
197 'vsize',
198 'weight',
199 ]
200 prevout_fields = [
201 'generated',
202 'height',
203 'value',
204 'scriptPubKey',
205 ]
206 script_pub_key_fields = [
207 'address',
208 'asm',
209 'hex',
210 'type',
211 ]
212 # node 0 & 2 with verbosity 1 & 2
213 for n, v in product([0, 2], [1, 2]):
214 self.log.info(f"Test getrawtransaction_verbosity {v} {'with' if n == 0 else 'without'} -txindex, with blockhash")
215 gottx = self.nodes[n].getrawtransaction(txid=tx, verbosity=v, blockhash=block1)
216 missing_fields = set(fields).difference(gottx.keys())
217 if missing_fields:
218 raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")
219
220 assert len(gottx['vin']) > 0
221 if v == 1:
222 assert 'fee' not in gottx
223 assert 'prevout' not in gottx['vin'][0]
224 if v == 2:
225 assert isinstance(gottx['fee'], Decimal)
226 assert 'prevout' in gottx['vin'][0]
227 prevout = gottx['vin'][0]['prevout']
228 script_pub_key = prevout['scriptPubKey']
229
230 missing_fields = set(prevout_fields).difference(prevout.keys())
231 if missing_fields:
232 raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")
233
234 missing_fields = set(script_pub_key_fields).difference(script_pub_key.keys())
235 if missing_fields:
236 raise AssertionError(f"fields {', '.join(missing_fields)} are not in transaction")
237
238 # check verbosity 2 without blockhash but with txindex
239 assert 'fee' in self.nodes[0].getrawtransaction(txid=tx, verbosity=2)
240 # check that coinbase has no fee or does not throw any errors for verbosity 2
241 coin_base = self.nodes[1].getblock(block1)['tx'][0]
242 gottx = self.nodes[1].getrawtransaction(txid=coin_base, verbosity=2, blockhash=block1)
243 assert 'fee' not in gottx
244 # check that verbosity 2 for a mempool tx will fallback to verbosity 1
245 # Do this with a pruned chain, as a regression test for https://github.com/bitcoin/bitcoin/pull/29003
246 self.generate(self.nodes[2], 400)
247 assert_greater_than(self.nodes[2].pruneblockchain(250), 0)
248 mempool_tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']
249 gottx = self.nodes[2].getrawtransaction(txid=mempool_tx, verbosity=2)
250 assert 'fee' not in gottx
251
252 def createrawtransaction_tests(self):
253 self.log.info("Test createrawtransaction")
254 # Test `createrawtransaction` required parameters
255 assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction)
256 assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [])
257
258 # Test `createrawtransaction` invalid extra parameters
259 assert_raises_rpc_error(-1, "createrawtransaction", self.nodes[0].createrawtransaction, [], {}, 0, False, 2, 3, 'foo')
260
261 # Test `createrawtransaction` invalid version parameters
262 assert_raises_rpc_error(-8, f"Invalid parameter, version out of range({TX_MIN_STANDARD_VERSION}~{TX_MAX_STANDARD_VERSION})", self.nodes[0].createrawtransaction, [], {}, 0, False, TX_MIN_STANDARD_VERSION - 1)
263 assert_raises_rpc_error(-8, f"Invalid parameter, version out of range({TX_MIN_STANDARD_VERSION}~{TX_MAX_STANDARD_VERSION})", self.nodes[0].createrawtransaction, [], {}, 0, False, TX_MAX_STANDARD_VERSION + 1)
264
265 # Test `createrawtransaction` invalid `inputs`
266 assert_raises_rpc_error(-3, "JSON value of type string is not of expected type array", self.nodes[0].createrawtransaction, 'foo', {})
267 assert_raises_rpc_error(-3, "JSON value of type string is not of expected type object", self.nodes[0].createrawtransaction, ['foo'], {})
268 assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", self.nodes[0].createrawtransaction, [{}], {})
269 assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].createrawtransaction, [{'txid': 'foo'}], {})
270 txid = "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844"
271 assert_raises_rpc_error(-8, f"txid must be hexadecimal string (not '{txid}')", self.nodes[0].createrawtransaction, [{'txid': txid}], {})
272 assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': TXID}], {})
273 assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", self.nodes[0].createrawtransaction, [{'txid': TXID, 'vout': 'foo'}], {})
274 assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", self.nodes[0].createrawtransaction, [{'txid': TXID, 'vout': -1}], {})
275 # sequence number out of range
276 for invalid_seq in [-1, 4294967296]:
277 inputs = [{'txid': TXID, 'vout': 1, 'sequence': invalid_seq}]
278 address = getnewdestination()[2]
279 outputs = {address: 1}
280 assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range',
281 self.nodes[0].createrawtransaction, inputs, outputs)
282 # with valid sequence number
283 for valid_seq in [1000, 4294967294]:
284 inputs = [{'txid': TXID, 'vout': 1, 'sequence': valid_seq}]
285 address = getnewdestination()[2]
286 outputs = {address: 1}
287 rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
288 decrawtx = self.nodes[0].decoderawtransaction(rawtx)
289 assert_equal(decrawtx['vin'][0]['sequence'], valid_seq)
290
291 # Test `createrawtransaction` invalid `outputs`
292 address = getnewdestination()[2]
293 assert_raises_rpc_error(-3, "JSON value of type string is not of expected type array", self.nodes[0].createrawtransaction, [], 'foo')
294 self.nodes[0].createrawtransaction(inputs=[], outputs={}) # Should not throw for backwards compatibility
295 self.nodes[0].createrawtransaction(inputs=[], outputs=[])
296 assert_raises_rpc_error(-8, "Data must be hexadecimal string", self.nodes[0].createrawtransaction, [], {'data': 'foo'})
297 assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].createrawtransaction, [], {'foo': 0})
298 assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].createrawtransaction, [], {address: 'foo'})
299 assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].createrawtransaction, [], {address: -1})
300 assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], multidict([(address, 1), (address, 1)]))
301 assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: %s" % address, self.nodes[0].createrawtransaction, [], [{address: 1}, {address: 1}])
302 assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], [{"data": 'aa'}, {"data": "bb"}])
303 assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", self.nodes[0].createrawtransaction, [], multidict([("data", 'aa'), ("data", "bb")]))
304 assert_raises_rpc_error(-8, "Invalid parameter, key-value pair must contain exactly one key", self.nodes[0].createrawtransaction, [], [{'a': 1, 'b': 2}])
305 assert_raises_rpc_error(-8, "Invalid parameter, key-value pair not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])
306
307 # Test `createrawtransaction` mismatch between sequence number(s) and `replaceable` option
308 assert_raises_rpc_error(-8, "Invalid parameter combination: Sequence number(s) contradict replaceable option",
309 self.nodes[0].createrawtransaction, [{'txid': TXID, 'vout': 0, 'sequence': MAX_BIP125_RBF_SEQUENCE+1}], {}, 0, True)
310
311 # Test `createrawtransaction` invalid `locktime`
312 assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].createrawtransaction, [], {}, 'foo')
313 assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, -1)
314 assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, 4294967296)
315
316 # Test `createrawtransaction` invalid `replaceable`
317 assert_raises_rpc_error(-3, "JSON value of type string is not of expected type bool", self.nodes[0].createrawtransaction, [], {}, 0, 'foo')
318
319 # Test that createrawtransaction accepts an array and object as outputs
320 # One output
321 tx = tx_from_hex(self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs={address: 99}))
322 assert_equal(len(tx.vout), 1)
323 assert_equal(
324 tx.serialize().hex(),
325 self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}]),
326 )
327 # Two outputs
328 address2 = getnewdestination()[2]
329 tx = tx_from_hex(self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)])))
330 assert_equal(len(tx.vout), 2)
331 assert_equal(
332 tx.serialize().hex(),
333 self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}, {address2: 99}]),
334 )
335 # Multiple mixed outputs
336 tx = tx_from_hex(self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=multidict([(address, 99), (address2, 99), ('data', '99')])))
337 assert_equal(len(tx.vout), 3)
338 assert_equal(
339 tx.serialize().hex(),
340 self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]),
341 )
342
343 for version in range(TX_MIN_STANDARD_VERSION, TX_MAX_STANDARD_VERSION + 1):
344 rawtx = self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)]), version=version)
345 tx = tx_from_hex(rawtx)
346 assert_equal(tx.version, version)
347
348 def sendrawtransaction_tests(self):
349 self.log.info("Test sendrawtransaction with missing input")
350 inputs = [{'txid': TXID, 'vout': 1}] # won't exist
351 address = getnewdestination()[2]
352 outputs = {address: 4.998}
353 rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
354 assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx)
355
356 self.log.info("Test sendrawtransaction exceeding, falling short of, and equaling maxburnamount")
357 max_burn_exceeded = "Unspendable output exceeds maximum configured by user (maxburnamount)"
358
359
360 # Test that spendable transaction with default maxburnamount (0) gets sent
361 tx = self.wallet.create_self_transfer()['tx']
362 tx_hex = tx.serialize().hex()
363 self.nodes[2].sendrawtransaction(hexstring=tx_hex)
364
365 # Test that datacarrier transaction with default maxburnamount (0) does not get sent
366 tx = self.wallet.create_self_transfer()['tx']
367 tx_val = 0.001
368 tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
369 tx_hex = tx.serialize().hex()
370 assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex)
371
372 # Test that oversized script gets rejected by sendrawtransaction
373 tx = self.wallet.create_self_transfer()['tx']
374 tx_val = 0.001
375 tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_FALSE] * 10001))]
376 tx_hex = tx.serialize().hex()
377 assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex)
378
379 # Test that script containing invalid opcode gets rejected by sendrawtransaction
380 tx = self.wallet.create_self_transfer()['tx']
381 tx_val = 0.01
382 tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_INVALIDOPCODE]))]
383 tx_hex = tx.serialize().hex()
384 assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex)
385
386 # Test a transaction where our burn exceeds maxburnamount
387 tx = self.wallet.create_self_transfer()['tx']
388 tx_val = 0.001
389 tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
390 tx_hex = tx.serialize().hex()
391 assert_raises_rpc_error(-25, max_burn_exceeded, self.nodes[2].sendrawtransaction, tx_hex, 0, 0.0009)
392
393 # Test a transaction where our burn falls short of maxburnamount
394 tx = self.wallet.create_self_transfer()['tx']
395 tx_val = 0.001
396 tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
397 tx_hex = tx.serialize().hex()
398 self.nodes[2].sendrawtransaction(hexstring=tx_hex, maxfeerate='0', maxburnamount='0.0011')
399
400 # Test a transaction where our burn equals maxburnamount
401 tx = self.wallet.create_self_transfer()['tx']
402 tx_val = 0.001
403 tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))]
404 tx_hex = tx.serialize().hex()
405 self.nodes[2].sendrawtransaction(hexstring=tx_hex, maxfeerate='0', maxburnamount='0.001')
406
407 def sendrawtransaction_testmempoolaccept_tests(self):
408 self.log.info("Test sendrawtransaction/testmempoolaccept with maxfeerate")
409 fee_exceeds_max = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"
410
411 # Test a transaction with a small fee.
412 # Fee rate is 0.00100000 BTC/kvB
413 tx = self.wallet.create_self_transfer(fee_rate=Decimal('0.00100000'))
414 # Thus, testmempoolaccept should reject
415 testres = self.nodes[2].testmempoolaccept([tx['hex']], 0.00001000)[0]
416 assert_equal(testres['allowed'], False)
417 assert_equal(testres['reject-reason'], 'max-fee-exceeded')
418 # and sendrawtransaction should throw
419 assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'], 0.00001000)
420 # and the following calls should both succeed
421 testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']])[0]
422 assert_equal(testres['allowed'], True)
423 self.nodes[2].sendrawtransaction(hexstring=tx['hex'])
424
425 # Test a transaction with a large fee.
426 # Fee rate is 0.20000000 BTC/kvB
427 tx = self.wallet.create_self_transfer(fee_rate=Decimal("0.20000000"))
428 # Thus, testmempoolaccept should reject
429 testres = self.nodes[2].testmempoolaccept([tx['hex']])[0]
430 assert_equal(testres['allowed'], False)
431 assert_equal(testres['reject-reason'], 'max-fee-exceeded')
432 # and sendrawtransaction should throw
433 assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'])
434 # and the following calls should both succeed
435 testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']], maxfeerate='0.20000000')[0]
436 assert_equal(testres['allowed'], True)
437 self.nodes[2].sendrawtransaction(hexstring=tx['hex'], maxfeerate='0.20000000')
438
439 self.log.info("Test sendrawtransaction/testmempoolaccept with tx outputs already in the utxo set")
440 self.generate(self.nodes[2], 1)
441 for node in self.nodes:
442 testres = node.testmempoolaccept([tx['hex']])[0]
443 assert_equal(testres['allowed'], False)
444 assert_equal(testres['reject-reason'], 'txn-already-known')
445 assert_raises_rpc_error(-27, 'Transaction outputs already in utxo set', node.sendrawtransaction, tx['hex'])
446
447 def decoderawtransaction_tests(self):
448 self.log.info("Test decoderawtransaction")
449 # witness transaction
450 encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
451 decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction
452 assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
453 assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction
454 # non-witness transaction
455 encrawtx = "01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000"
456 decrawtx = self.nodes[0].decoderawtransaction(encrawtx, False) # decode as non-witness transaction
457 assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
458 # known ambiguous transaction in the chain (see https://github.com/bitcoin/bitcoin/issues/20579)
459 coinbase = "03c68708046ff8415c622f4254432e434f4d2ffabe6d6de1965d02c68f928e5b244ab1965115a36f56eb997633c7f690124bbf43644e23080000000ca3d3af6d005a65ff0200fd00000000"
460 encrawtx = f"020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4b{coinbase}" \
461 "ffffffff03f4c1fb4b0000000016001497cfc76442fe717f2a3f0cc9c175f7561b6619970000000000000000266a24aa21a9ed957d1036a80343e0d1b659497e1b48a38ebe876a056d45965fac4a85cda84e1900000000000000002952534b424c4f434b3a8e092581ab01986cbadc84f4b43f4fa4bb9e7a2e2a0caf9b7cf64d939028e22c0120000000000000000000000000000000000000000000000000000000000000000000000000"
462 decrawtx = self.nodes[0].decoderawtransaction(encrawtx)
463 decrawtx_wit = self.nodes[0].decoderawtransaction(encrawtx, True)
464 assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # fails to decode as non-witness transaction
465 assert_equal(decrawtx, decrawtx_wit) # the witness interpretation should be chosen
466 assert_equal(decrawtx['vin'][0]['coinbase'], coinbase)
467
468 def transaction_version_number_tests(self):
469 self.log.info("Test transaction version numbers")
470
471 # Test the minimum transaction version number that fits in a signed 32-bit integer.
472 # As transaction version is serialized unsigned, this should convert to its unsigned equivalent.
473 tx = CTransaction()
474 tx.version = 0x80000000
475 rawtx = tx.serialize().hex()
476 decrawtx = self.nodes[0].decoderawtransaction(rawtx)
477 assert_equal(decrawtx['version'], 0x80000000)
478
479 # Test the maximum transaction version number that fits in a signed 32-bit integer.
480 tx = CTransaction()
481 tx.version = 0x7fffffff
482 rawtx = tx.serialize().hex()
483 decrawtx = self.nodes[0].decoderawtransaction(rawtx)
484 assert_equal(decrawtx['version'], 0x7fffffff)
485
486 # Test the minimum transaction version number that fits in an unsigned 32-bit integer.
487 tx = CTransaction()
488 tx.version = 0
489 rawtx = tx.serialize().hex()
490 decrawtx = self.nodes[0].decoderawtransaction(rawtx)
491 assert_equal(decrawtx['version'], 0)
492
493 # Test the maximum transaction version number that fits in an unsigned 32-bit integer.
494 tx = CTransaction()
495 tx.version = 0xffffffff
496 rawtx = tx.serialize().hex()
497 decrawtx = self.nodes[0].decoderawtransaction(rawtx)
498 assert_equal(decrawtx['version'], 0xffffffff)
499
500 if __name__ == '__main__':
501 RawTransactionsTest(__file__).main()
502