/ test / functional / rpc_rawtransaction.py
rpc_rawtransaction.py
  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()