wallet_create_tx.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2018-2022 The Limenka 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 decimal import Decimal
   7  
   8  from test_framework.messages import (
   9      tx_from_hex,
  10  )
  11  from test_framework.test_framework import LimenkaTestFramework
  12  from test_framework.util import (
  13      assert_equal,
  14      assert_raises_rpc_error,
  15  )
  16  from test_framework.blocktools import (
  17      TIME_GENESIS_BLOCK,
  18  )
  19  
  20  
  21  class CreateTxWalletTest(LimenkaTestFramework):
  22      def add_options(self, parser):
  23          self.add_wallet_options(parser)
  24  
  25      def set_test_params(self):
  26          self.setup_clean_chain = True
  27          self.num_nodes = 1
  28  
  29      def skip_test_if_missing_module(self):
  30          self.skip_if_no_wallet()
  31  
  32      def run_test(self):
  33          self.log.info('Create some old blocks')
  34          self.nodes[0].setmocktime(TIME_GENESIS_BLOCK)
  35          self.generate(self.nodes[0], 200)
  36          self.nodes[0].setmocktime(0)
  37  
  38          self.test_anti_fee_sniping()
  39          self.test_tx_size_too_large()
  40          self.test_create_too_long_mempool_chain()
  41          self.test_version3()
  42          self.test_setfeerate()
  43  
  44      def test_anti_fee_sniping(self):
  45          self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
  46  
  47          # sendtoaddress RPC
  48          assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
  49          txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
  50          tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
  51          assert_equal(tx['locktime'], 0)
  52  
  53          # send RPC
  54          outputs = [{self.nodes[0].getnewaddress(): 1}]
  55          res = self.nodes[0].send(outputs=outputs)
  56          assert(res["complete"])
  57          tx = self.nodes[0].gettransaction(txid=res['txid'], verbose=True)['decoded']
  58          assert_equal(tx['locktime'], 0)
  59  
  60          # sendall RPC (don't actually empty the wallet)
  61          res = self.nodes[0].sendall(recipients=[self.nodes[0].getnewaddress()], add_to_wallet=False)
  62          assert(res["complete"])
  63          tx = self.nodes[0].decoderawtransaction(res['hex'])
  64          assert_equal(tx['locktime'], 0)
  65  
  66          self.log.info('Check that anti-fee-sniping is enabled when we mine a recent block')
  67          self.generate(self.nodes[0], 1)
  68          txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
  69          tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded']
  70          assert 0 < tx['locktime'] <= 201
  71  
  72          # send RPC
  73          outputs = [{self.nodes[0].getnewaddress(): 1}]
  74          res = self.nodes[0].send(outputs=outputs)
  75          assert(res["complete"])
  76          tx = self.nodes[0].gettransaction(txid=res['txid'], verbose=True)['decoded']
  77          assert 0 < tx['locktime'] <= 201
  78  
  79          # sendall RPC
  80          res = self.nodes[0].sendall(recipients=[self.nodes[0].getnewaddress()], add_to_wallet=False)
  81          assert(res["complete"])
  82          tx = self.nodes[0].decoderawtransaction(res['hex'])
  83          assert 0 < tx['locktime'] <= 201
  84  
  85      def test_tx_size_too_large(self):
  86          # More than 10kB of outputs, so that we hit -maxtxfee with a high feerate
  87          outputs = {self.nodes[0].getnewaddress(address_type='bech32'): 0.000025 for _ in range(400)}
  88          raw_tx = self.nodes[0].createrawtransaction(inputs=[], outputs=outputs)
  89          msg = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"
  90  
  91          for fee_setting in ['-minrelaytxfee=0.01', '-mintxfee=0.01', '-paytxfee=0.01']:
  92              self.log.info('Check maxtxfee in combination with {}'.format(fee_setting))
  93              self.restart_node(0, extra_args=[fee_setting])
  94              assert_raises_rpc_error(
  95                  -6,
  96                  "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
  97                  lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
  98              )
  99              assert_raises_rpc_error(
 100                  -4,
 101                  "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 102                  lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
 103              )
 104  
 105          self.log.info('Check maxtxfee in combination with settxfee')
 106          self.restart_node(0)
 107          self.nodes[0].settxfee(0.01)
 108          assert_raises_rpc_error(
 109              -6,
 110              "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 111              lambda: self.nodes[0].sendmany(dummy="", amounts=outputs),
 112          )
 113          assert_raises_rpc_error(
 114              -4,
 115              "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
 116              lambda: self.nodes[0].fundrawtransaction(hexstring=raw_tx),
 117          )
 118          self.nodes[0].settxfee(0)
 119  
 120          self.log.info('Check maxtxfee in combination with setfeerate (sat/vB)')
 121          self.nodes[0].setfeerate(1000)
 122          assert_raises_rpc_error(-6, msg, self.nodes[0].sendmany, dummy="", amounts=outputs)
 123          assert_raises_rpc_error(-4, msg, self.nodes[0].fundrawtransaction, hexstring=raw_tx)
 124          self.nodes[0].setfeerate(0)
 125  
 126      def test_create_too_long_mempool_chain(self):
 127          self.log.info('Check too-long mempool chain error')
 128          df_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
 129  
 130          self.nodes[0].createwallet("too_long")
 131          test_wallet = self.nodes[0].get_wallet_rpc("too_long")
 132  
 133          tx_data = df_wallet.send(outputs=[{test_wallet.getnewaddress(): 25}], options={"change_position": 0})
 134          txid = tx_data['txid']
 135          vout = 1
 136  
 137          self.nodes[0].syncwithvalidationinterfacequeue()
 138          options = {"change_position": 0, "add_inputs": False}
 139          for i in range(1, 25):
 140              options['inputs'] = [{'txid': txid, 'vout': vout}]
 141              tx_data = test_wallet.send(outputs=[{test_wallet.getnewaddress(): 25 - i}], options=options)
 142              txid = tx_data['txid']
 143  
 144          # Sending one more chained transaction will fail
 145          options = {"minconf": 0, "include_unsafe": True, 'add_inputs': True}
 146          assert_raises_rpc_error(-4, "Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool",
 147                                  test_wallet.send, outputs=[{test_wallet.getnewaddress(): 0.3}], options=options)
 148  
 149          test_wallet.unloadwallet()
 150  
 151      def test_version3(self):
 152          self.log.info('Check wallet does not create transactions with version=3 yet')
 153          wallet_rpc = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
 154  
 155          self.nodes[0].createwallet("version3")
 156          wallet_v3 = self.nodes[0].get_wallet_rpc("version3")
 157  
 158          tx_data = wallet_rpc.send(outputs=[{wallet_v3.getnewaddress(): 25}], options={"change_position": 0})
 159          wallet_tx_data = wallet_rpc.gettransaction(tx_data["txid"])
 160          tx_current_version = tx_from_hex(wallet_tx_data["hex"])
 161  
 162          # While version=3 transactions are standard, the CURRENT_VERSION is 2.
 163          # This test can be removed if CURRENT_VERSION is changed, and replaced with tests that the
 164          # wallet handles TRUC rules properly.
 165          assert_equal(tx_current_version.version, 2)
 166          wallet_v3.unloadwallet()
 167  
 168      def test_setfeerate(self):
 169          self.log.info("Test setfeerate")
 170          self.restart_node(0, extra_args=[
 171              "-incrementalrelayfee=0.00001",
 172              "-mintxfee=0.00003141",  # 3.141 sat/vB
 173          ])
 174          node = self.nodes[0]
 175  
 176          def test_response(*, requested=0, expected=0, error=None, msg):
 177              assert_equal(node.setfeerate(requested), {"wallet_name": self.default_wallet_name, "fee_rate": expected, ("error" if error else "result"): msg})
 178  
 179          # Test setfeerate with 10.0001 (CFeeRate rounding), "10.001" and "4" sat/vB
 180          test_response(requested=10.0001, expected=10, msg="Fee rate for transactions with this wallet successfully set to 10.000 sat/vB")
 181          assert_equal(node.getwalletinfo()["paytxfee"], Decimal("0.00010000"))
 182          test_response(requested="10.001", expected=Decimal("10.001"), msg="Fee rate for transactions with this wallet successfully set to 10.001 sat/vB")
 183          assert_equal(node.getwalletinfo()["paytxfee"], Decimal("0.00010001"))
 184          test_response(requested="4", expected=4, msg="Fee rate for transactions with this wallet successfully set to 4.000 sat/vB")
 185          assert_equal(node.getwalletinfo()["paytxfee"], Decimal("0.00004000"))
 186  
 187          # Test setfeerate with too-high/low values returns expected errors
 188          test_response(requested=Decimal("10000.001"), expected=4, error=True, msg="The requested fee rate of 10000.001 sat/vB cannot be greater than the wallet max fee rate of 10000.000 sat/vB. The current setting of 4.000 sat/vB for this wallet remains unchanged.")
 189          test_response(requested=Decimal("0.999"), expected=4, error=True, msg="The requested fee rate of 0.999 sat/vB cannot be less than the minimum relay fee rate of 1.000 sat/vB. The current setting of 4.000 sat/vB for this wallet remains unchanged.")
 190          test_response(requested=Decimal("3.140"), expected=4, error=True, msg="The requested fee rate of 3.140 sat/vB cannot be less than the wallet min fee rate of 3.141 sat/vB. The current setting of 4.000 sat/vB for this wallet remains unchanged.")
 191          assert_equal(node.getwalletinfo()["paytxfee"], Decimal("0.00004000"))
 192  
 193          # Test setfeerate to 3.141 sat/vB
 194          test_response(requested=3.141, expected=Decimal("3.141"), msg="Fee rate for transactions with this wallet successfully set to 3.141 sat/vB")
 195          assert_equal(node.getwalletinfo()["paytxfee"], Decimal("0.00003141"))
 196  
 197          # Test setfeerate with values non-representable by CFeeRate
 198          for invalid_value in [0.00000001, 0.0009, 0.00099999]:
 199              assert_raises_rpc_error(-3, "Invalid amount", node.setfeerate, amount=invalid_value)
 200  
 201          # Test setfeerate with values rejected by ParseFixedPoint() called in AmountFromValue()
 202          for invalid_value in ["", 0.000000001, "1.111111111", 11111111111]:
 203              assert_raises_rpc_error(-3, "Invalid amount", node.setfeerate, amount=invalid_value)
 204  
 205          # Test deactivating setfeerate
 206          test_response(msg="Fee rate for transactions with this wallet successfully unset. By default, automatic fee selection will be used.")
 207          assert_equal(node.getwalletinfo()["paytxfee"], 0)
 208  
 209          # Test currently-unset setfeerate with too-high/low values returns expected errors
 210          test_response(requested=Decimal("10000.001"), error=True, msg="The requested fee rate of 10000.001 sat/vB cannot be greater than the wallet max fee rate of 10000.000 sat/vB. The current setting of 0 (unset) for this wallet remains unchanged.")
 211          assert_equal(node.getwalletinfo()["paytxfee"], 0)
 212          test_response(requested=Decimal("0.999"), error=True, msg="The requested fee rate of 0.999 sat/vB cannot be less than the minimum relay fee rate of 1.000 sat/vB. The current setting of 0 (unset) for this wallet remains unchanged.")
 213          test_response(requested=Decimal("3.140"), error=True, msg="The requested fee rate of 3.140 sat/vB cannot be less than the wallet min fee rate of 3.141 sat/vB. The current setting of 0 (unset) for this wallet remains unchanged.")
 214          assert_equal(node.getwalletinfo()["paytxfee"], 0)
 215  
 216  
 217  if __name__ == '__main__':
 218      CreateTxWalletTest(__file__).main()
 219