Allow users to specify input weights when funding a transaction (wallet, rpc/rest/zmq)

https://github.com/bitcoin/bitcoin/pull/23201

Host: glozow  -  PR author: achow101

Notes

  • Funding a transaction involves selecting inputs with a total amount that covers both the payment(s) and the fees for the transaction itself. The target feerate is calculated at the beginning, and the fees depend on the total size of the transaction.

  • In some use cases, users may want to fund a transaction with external inputs, i.e., inputs that are not controlled by the user themselves, but some external wallet such as that of a LN channel counterparty. The challenge in this scenario is accounting for these inputs when funding the fees of the transaction - the wallet needs to know their size.

    • Given solving data such as public keys, scripts, or descriptors, the wallet can approximate the size of the input and corresponding witness data. For example, this stackexchange post breaks down the possible sizes of a P2PKH input.

    • PR #17211 added support for allowing users to provide solving data to help the wallet determine the size of external input(s).

    • Some sizes might differ depending on how the external wallet generates the signature. In these cases, the wallet uses the maximum possible size to avoid underestimating the fees needed to reach the target feerate.

    • Still, solving data might not be available and external inputs may be nonstandard.

  • PR #23201 adds support for specifying the weights of external inputs in the wallet RPCs send, walletcreatefundedpsbt, and fundrawtransaction. This allows the wallet to take these inputs into account when funding the transaction at a target feerate, even if it doesn’t have the solving data for calculating the size itself.

    • This is achieved by adding a map from the input’s outpoint to weight in CCoinControl.

    • If a user provides both solving data and input weights, the provided weight overrides the size calculated using solving data.

  • Raw transactions are serialized in a specific format which includes lengths and sizes (e.g. number of inputs in vin and number of bytes in the signature script) represented as Compact Size Unsigned Integers, which vary in length depending on the value.

Questions

  1. Did you review the PR? Concept ACK, approach ACK, tested ACK, or NACK?

  2. What are some use cases of allowing external inputs to be used in send, walletcreatefundedpsbt, fundrawtransaction, and bumpfee?

  3. Why might a user want to specify input weights instead of using the existing solving_data option?

  4. Why does FundTransaction() need to know the external inputs ahead of time at all?

  5. In the interface modified by this PR, how would a user call {send, walletcreatefundedpsbt, fundrawtransaction} to specify a maximum input weight?

  6. The RPCs will throw a JSONRPCError: RPC_INVALID_PARAMETER if the specified weight is below 160. Why can’t the weight of an input be less than 160?

  7. Quiz: Given that an external input is a {P2PKH, P2WPKH, P2WSH, P2TR}, can you calculate the maximum weight you need to add to the transaction you’re funding?

  8. What is the purpose of CCoinControl? What are the different purposes of CCoinControl versus CoinSelectionParams?

  9. What does the FillInputToWeight() function do?

  10. Why does FillInputToWeight subtract the size of the Compact Size Uint from the add_weight?