Repository: bitcoin/bitcoin
File: test/functional/wallet_sendall.py (Python)

Code before:
        assert_raises_rpc_error(-6,
            "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.",
            self.wallet.sendall,
            recipients=[self.remainder_target],
            options={"maxconf": 1})

        self.log.info("Test sendall only spends utxos with a specified number of confirmations when maxconf is used")
        self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"maxconf":4})
        assert_equal(len(self.wallet.listunspent()), 1)
        assert_equal(self.wallet.listunspent()[0]['confirmations'], 6)

    # This tests needs to be the last one otherwise @cleanup will fail with "Transaction too large" error
    def sendall_fails_with_transaction_too_large(self):
        self.log.info("Test that sendall fails if resulting transaction is too large")

        # Force the wallet to bulk-generate the addresses we'll need
        self.wallet.keypoolrefill(1600)

        # create many inputs
        outputs = {self.wallet.getnewaddress(): 0.000025 for _ in range(1600)}
        self.def_wallet.sendmany(amounts=outputs)
        self.generate(self.nodes[0], 1)

        assert_raises_rpc_error(
                -4,
                "Transaction too large.",
                self.wallet.sendall,
                recipients=[self.remainder_target])

    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.recipient = self.def_wallet.getnewaddress() # payee for a specific amount
        self.remainder_target = self.def_wallet.getnewaddress() # address that receives everything left after payments and fees
        self.split_target = self.def_wallet.getnewaddress() # 2nd target when splitting rest

        # Test cleanup
        self.test_cleanup()

        # Basic sweep: everything to one address
        self.sendall_two_utxos()

        # Split remainder to two addresses with equal amounts
        self.sendall_split()

        # Pay recipient and sweep remainder
        self.sendall_and_spend()

        # sendall fails if no recipient has unspecified amount

Review comment (bug):
In c9746711:

Need to flush the validation queue before checking the wallet balance. The transaction could have not been processed by the validation interface worker thread. Call `self.wallet.syncwithvalidationinterfacequeue()`.

(saw it failing locally).

Code after:
        assert_raises_rpc_error(-6,
            "Total value of UTXO pool too low to pay for transaction. Try using lower feerate or excluding uneconomic UTXOs with 'send_max' option.",
            self.wallet.sendall,
            recipients=[self.remainder_target],
            options={"maxconf": 1})

        self.log.info("Test sendall only spends utxos with a specified number of confirmations when maxconf is used")
        self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"maxconf":4})
        assert_equal(len(self.wallet.listunspent()), 1)
        assert_equal(self.wallet.listunspent()[0]['confirmations'], 6)

    @cleanup
    def sendall_spends_unconfirmed_change(self):
        self.log.info("Test that sendall spends unconfirmed change")
        self.add_utxos([17])
        self.wallet.sendtoaddress(self.remainder_target, 10)
        assert_greater_than(self.wallet.getbalances()["mine"]["trusted"], 6)
        self.test_sendall_success(sendall_args = [self.remainder_target])

        assert_equal(self.wallet.getbalance(), 0)

    @cleanup
    def sendall_spends_unconfirmed_inputs_if_specified(self):
        self.log.info("Test that sendall spends specified unconfirmed inputs")
        self.def_wallet.sendtoaddress(self.wallet.getnewaddress(), 17)
        self.wallet.syncwithvalidationinterfacequeue()
        assert_equal(self.wallet.getbalances()["mine"]["untrusted_pending"], 17)
        unspent = self.wallet.listunspent(minconf=0)[0]

        self.wallet.sendall(recipients=[self.remainder_target], inputs=[unspent])
        assert_equal(self.wallet.getbalance(), 0)

    @cleanup
    def sendall_does_ancestor_aware_funding(self):
        self.log.info("Test that sendall does ancestor aware funding for unconfirmed inputs")

        # higher parent feerate
        self.def_wallet.sendtoaddress(address=self.wallet.getnewaddress(), amount=17, fee_rate=20)
        self.wallet.syncwithvalidationinterfacequeue()

        assert_equal(self.wallet.getbalances()["mine"]["untrusted_pending"], 17)
        unspent = self.wallet.listunspent(minconf=0)[0]

        parent_txid = unspent["txid"]
        assert_equal(self.wallet.gettransaction(parent_txid)["confirmations"], 0)

        res_1 = self.wallet.sendall(recipients=[self.def_wallet.getnewaddress()], inputs=[unspent], fee_rate=20, add_to_wallet=False, lock_unspents=True)
        child_hex = res_1["hex"]

        child_tx = self.wallet.decoderawtransaction(child_hex)
        higher_parent_feerate_amount = child_tx["vout"][0]["value"]