Merge bitcoin/bitcoin#28560: wallet, rpc: FundTransaction refactor

18ad1b9142 refactor: pass CRecipient to FundTransaction (josibake)
5ad19668db refactor: simplify `CreateRecipients` (josibake)
47353a608d refactor: remove out param from `ParseRecipients` (josibake)
f7384b921c refactor: move parsing to new function (josibake)
6f569ac903 refactor: move normalization to new function (josibake)
435fe5cd96 test: add tests for fundrawtx and sendmany rpcs (josibake)

Pull request description:

  ## Motivation

  The primary motivation for this PR is to enable `FundTransaction` to take a vector of `CRecipient` objects to allow passing BIP352 silent payment addresses to RPCs that use `FundTransaction` (e.g. `send`, `walletcreatefundedpsbt`). To do that, SFFO logic needs to be moved out of `FundTransaction` so the `CRecipient` objects with the correct SFFO information can be created and then passed to `FundTransaction`.

  As a secondary motivation, this PR moves the SFFO stuff closer to the caller, making the code cleaner and easier to understand. This is done by having a single function which parses RPC inputs for SFFO and consistently using the `set<int>` method for communicating SFFO.

  I'm also not convinced we need to pass a full `CMutableTx` object to `FundTransaction`, but I'm leaving that for a follow-up PR/discussion, as its not a blocker for silent payments.

ACKs for top commit:
  S3RK:
    reACK 18ad1b9142
  josibake:
    > According to my `range-diff` nothing changed. reACK [18ad1b9](18ad1b9142)
  achow101:
    ACK 18ad1b9142

Tree-SHA512: d61f017cf7d98489ef216475b68693fd77e7b53a26a6477dcd73e7e5ceff5036b2d21476e377839e710bb73644759d42c4f9f4b14ed96b3e56ed87b07aa6d1a7
This commit is contained in:
Ava Chow
2024-01-23 16:32:27 -05:00
9 changed files with 217 additions and 95 deletions

View File

@@ -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',

View File

@@ -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."""

View File

@@ -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()