diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 9c8f0eca262..fcec2ecdbef 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -333,6 +333,8 @@ BASE_SCRIPTS = [ 'wallet_send.py --descriptors', 'wallet_sendall.py --legacy-wallet', 'wallet_sendall.py --descriptors', + 'wallet_sendmany.py --descriptors', + 'wallet_sendmany.py --legacy-wallet', 'wallet_create_tx.py --descriptors', 'wallet_inactive_hdchains.py --legacy-wallet', 'wallet_spend_unconfirmed.py', diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index a331ba997e9..d886a59ac15 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -8,10 +8,13 @@ from decimal import Decimal from itertools import product from math import ceil +from test_framework.address import address_to_scriptpubkey from test_framework.descriptors import descsum_create from test_framework.messages import ( COIN, + CTransaction, + CTxOut, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -147,6 +150,34 @@ class RawTransactionsTest(BitcoinTestFramework): self.test_22670() self.test_feerate_rounding() self.test_input_confs_control() + self.test_duplicate_outputs() + + def test_duplicate_outputs(self): + self.log.info("Test deserializing and funding a transaction with duplicate outputs") + self.nodes[1].createwallet("fundtx_duplicate_outputs") + w = self.nodes[1].get_wallet_rpc("fundtx_duplicate_outputs") + + addr = w.getnewaddress(address_type="bech32") + self.nodes[0].sendtoaddress(addr, 5) + self.generate(self.nodes[0], 1) + + address = self.nodes[0].getnewaddress("bech32") + tx = CTransaction() + tx.vin = [] + tx.vout = [CTxOut(1 * COIN, bytearray(address_to_scriptpubkey(address)))] * 2 + tx.nLockTime = 0 + tx_hex = tx.serialize().hex() + res = w.fundrawtransaction(tx_hex, add_inputs=True) + signed_res = w.signrawtransactionwithwallet(res["hex"]) + txid = w.sendrawtransaction(signed_res["hex"]) + assert self.nodes[1].getrawtransaction(txid) + + self.log.info("Test SFFO with duplicate outputs") + + res_sffo = w.fundrawtransaction(tx_hex, add_inputs=True, subtractFeeFromOutputs=[0,1]) + signed_res_sffo = w.signrawtransactionwithwallet(res_sffo["hex"]) + txid_sffo = w.sendrawtransaction(signed_res_sffo["hex"]) + assert self.nodes[1].getrawtransaction(txid_sffo) def test_change_position(self): """Ensure setting changePosition in fundraw with an exact match is handled properly.""" diff --git a/test/functional/wallet_sendmany.py b/test/functional/wallet_sendmany.py new file mode 100755 index 00000000000..57519931433 --- /dev/null +++ b/test/functional/wallet_sendmany.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test the sendmany RPC command.""" + +from test_framework.test_framework import BitcoinTestFramework + +class SendmanyTest(BitcoinTestFramework): + # Setup and helpers + def add_options(self, parser): + self.add_wallet_options(parser) + + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + + def test_sffo_repeated_address(self): + addr_1 = self.wallet.getnewaddress() + addr_2 = self.wallet.getnewaddress() + addr_3 = self.wallet.getnewaddress() + + self.log.info("Test using duplicate address in SFFO argument") + self.def_wallet.sendmany(dummy='', amounts={addr_1: 1, addr_2: 1}, subtractfeefrom=[addr_1, addr_1, addr_1]) + self.log.info("Test using address not present in tx.vout in SFFO argument") + self.def_wallet.sendmany(dummy='', amounts={addr_1: 1, addr_2: 1}, subtractfeefrom=[addr_3]) + + def run_test(self): + self.nodes[0].createwallet("activewallet") + self.wallet = self.nodes[0].get_wallet_rpc("activewallet") + self.def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name) + self.generate(self.nodes[0], 101) + + self.test_sffo_repeated_address() + + +if __name__ == '__main__': + SendmanyTest().main()