/ test / functional / wallet_create_tx.py
wallet_create_tx.py
  1  #!/usr/bin/env python3
  2  # Copyright (c) 2018-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  
  6  from test_framework.messages import (
  7      tx_from_hex,
  8  )
  9  from test_framework.test_framework import BitcoinTestFramework
 10  from test_framework.util import (
 11      assert_equal,
 12      assert_raises_rpc_error,
 13  )
 14  from test_framework.blocktools import (
 15      TIME_GENESIS_BLOCK,
 16  )
 17  
 18  from decimal import Decimal
 19  
 20  class CreateTxWalletTest(BitcoinTestFramework):
 21      def set_test_params(self):
 22          self.setup_clean_chain = True
 23          self.num_nodes = 1
 24          self.extra_args = [[]]
 25  
 26      def skip_test_if_missing_module(self):
 27          self.skip_if_no_wallet()
 28  
 29      def run_test(self):
 30          self.log.info('Create some old blocks')
 31          self.nodes[0].setmocktime(TIME_GENESIS_BLOCK)
 32          self.generate(self.nodes[0], 200)
 33          self.nodes[0].setmocktime(0)
 34  
 35          self.test_anti_fee_sniping()
 36          self.test_tx_size_too_large()
 37          self.test_create_too_long_mempool_chain()
 38          self.test_version3()
 39  
 40      def test_anti_fee_sniping(self):
 41          self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
 42          assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
 43          txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
 44          tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
 45          assert_equal(tx['locktime'], 0)
 46  
 47          self.log.info('Check that anti-fee-sniping is enabled when we mine a recent block')
 48          self.generate(self.nodes[0], 1)
 49          txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
 50          tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
 51          assert 0 < tx['locktime'] <= 201
 52  
 53      def test_tx_size_too_large(self):
 54          # More than 10kB of outputs, so that we hit -maxtxfee with a high feerate
 55          outputs = {self.nodes[0].getnewaddress(address_type='bech32'): 0.000025 for _ in range(400)}
 56          raw_tx = self.nodes[0].createrawtransaction(inputs=[], outputs=outputs)
 57  
 58          for fee_setting in ['-minrelaytxfee=0.01', '-mintxfee=0.01']:
 59              self.log.info('Check maxtxfee in combination with {}'.format(fee_setting))
 60              self.restart_node(0, extra_args=[fee_setting])
 61              assert_raises_rpc_error(
 62                  -6,
 63                  "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 64                  lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
 65              )
 66              assert_raises_rpc_error(
 67                  -4,
 68                  "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 69                  lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
 70              )
 71  
 72          # Hit maxtxfee with explicit fee rate
 73          self.log.info('Check maxtxfee in combination with explicit fee_rate=1000 sat/vB')
 74  
 75          fee_rate_sats_per_vb = Decimal('0.01') * Decimal(1e8) / 1000  # Convert 0.01 BTC/kvB to sat/vB
 76  
 77          assert_raises_rpc_error(
 78              -6,
 79              "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 80              lambda: self.nodes[0].sendmany(dummy="", amounts=outputs, fee_rate=fee_rate_sats_per_vb),
 81          )
 82          assert_raises_rpc_error(
 83              -4,
 84              "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 85              lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx, options={'fee_rate': fee_rate_sats_per_vb}),
 86          )
 87  
 88      def test_create_too_long_mempool_chain(self):
 89          self.log.info('Check too-long mempool chain error')
 90          df_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
 91  
 92          self.nodes[0].createwallet("too_long")
 93          test_wallet = self.nodes[0].get_wallet_rpc("too_long")
 94  
 95          tx_data = df_wallet.send(outputs=[{test_wallet.getnewaddress(): 25}], options={"change_position": 0})
 96          txid = tx_data['txid']
 97          vout = 1
 98  
 99          self.nodes[0].syncwithvalidationinterfacequeue()
100          options = {"change_position": 0, "add_inputs": False}
101          for i in range(1, 25):
102              options['inputs'] = [{'txid': txid, 'vout': vout}]
103              tx_data = test_wallet.send(outputs=[{test_wallet.getnewaddress(): 25 - i}], options=options)
104              txid = tx_data['txid']
105  
106          # Sending one more chained transaction will fail
107          options = {"minconf": 0, "include_unsafe": True, 'add_inputs': True}
108          assert_raises_rpc_error(-4, "Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool",
109                                  test_wallet.send, outputs=[{test_wallet.getnewaddress(): 0.3}], options=options)
110  
111          test_wallet.unloadwallet()
112  
113      def test_version3(self):
114          self.log.info('Check wallet does not create transactions with version=3 yet')
115          wallet_rpc = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
116  
117          self.nodes[0].createwallet("version3")
118          wallet_v3 = self.nodes[0].get_wallet_rpc("version3")
119  
120          tx_data = wallet_rpc.send(outputs=[{wallet_v3.getnewaddress(): 25}], options={"change_position": 0})
121          wallet_tx_data = wallet_rpc.gettransaction(tx_data["txid"])
122          tx_current_version = tx_from_hex(wallet_tx_data["hex"])
123  
124          # While version=3 transactions are standard, the CURRENT_VERSION is 2.
125          # This test can be removed if CURRENT_VERSION is changed, and replaced with tests that the
126          # wallet handles TRUC rules properly.
127          assert_equal(tx_current_version.version, 2)
128          wallet_v3.unloadwallet()
129  
130  
131  if __name__ == '__main__':
132      CreateTxWalletTest(__file__).main()