- Did you review the PR, what did you think (ACK, NACK, etc)? What was your review process?
- What is the use case for the
TxBuilder::add_foreign_utxoAPI? (1 pt)
ans: The normalTxBuilder::add_utxoonly accepts wallet UTXOs that are unspent, but there are times when we might want to include inputs from other wallets if building transactions collaboratively with other parties. For that we haveadd_foreign_utxo. - What is
Wallet::build_fee_bumpdesigned to accomplish? Briefly describe the high-level steps (2 pt)
ans:build_fee_bumptakes a transaction ID representing the tx to be fee-bumped (via RBF) and returns a newTxBuilderpopulated with the parameters of the original transaction (version, recipients, etc).
Steps:- Retrieve the original transaction data from the wallet
- Recreate the original UTXOs by "processing the inputs"
- Retain the original parameters (version, recipients) + include the previous fee
- Make a best effort to remove the change output, since raising the fee means the value of the change has to be recalculated
- In what real world situation could the issue arise, i.e., failing to fee-bump a transaction due to a missing parent (1 pt)
ans: As outlined in issue #325, if the original transaction spends an output of a parent that is external to the wallet, then the parent would be missing. Normally this isn't an issue when the parent is another wallet tx, but it's possible to create a tx sweeping a P2A output of a foreign tx which by definition is "anyone-can-spend". In that case we won't have the parent by default. This situation is common in some off-chain protocols such as Ark.
- Issue #325 states that
build_fee_bumpreturns an error if the P2A spend doesn't originate in the wallet. Prior to the fix, which line(s) of code proved to be problematic? What is the error returned? (2 pt)
ans: L1758 begins withgraph.get_tx()passing the txid of the input's previous outpoint (i.e. the parent transaction)
ans: Ifget_txreturns None, then we returnBuildFeeBumpError::UnknownUtxofrom the map closure. - How is the fix implemented? Can you think of another approach? (2 pt)
ans: We query the TxGraph for the P2A output itself, which can exist in the graph without its containing transaction.
ans: Issue #325 mentions another approach that involves removing (i.e. evicting) the original tx from the wallet and creating the replacement at a higher feerate usingadd_foreign_utxo. This works around thebuild_fee_bumplimitation but is more of a manual intervention. - Why is it reasonable to assume that previous txouts are available even when the parent transaction isn't part of the wallet? What happens if the previous txout isn't available? (2 pt)
ans: The previous txouts are needed to calculate the fee/feerate of the original transaction
ans: Otherwise aBuildFeeBumpError::FeeRateUnavailableerror will occur - What determines whether the original transaction input refers to a
Utxo::LocalorUtxo::ForeignUTXO? hint: what can we say about the previous output's script pubkey? (1 pt)
ans: If the previous output's script pubkey is indexed by a wallet keychain, thenindex_of_spkwill returnSome((keychain, derivation_index))indicating the script is derived from a wallet descriptor and the UTXO is local to the wallet, otherwise it must be foreign. - Under what condition is the full parent transaction still required? (1 pt)
ans: In case the UTXO we're looking for isUtxo::Local, we require the parent transaction in order to assign a value of theLocalOutput::chain_position. - How does
test_bump_fee_pay_to_anchor_foreign_utxotest that the issue is resolved? Did you spot any flaws in the test setup or execution? (2 pt)
ans: The test checks thatbuild_fee_bumpsucceeds when the original transaction contains a P2A spend
ans: We also check that the replacement includes the expected outpoint among the inputs
ans: A potential flaw is that the test hardcodes a satisfaction weight of 71 WU, although we know that P2A outputs don't require a signature to spend
bonus:
- What security considerations must be taken into account when using
add_foreign_utxo?
ans: In case the PSBT input doesn't include the full previous transaction (non-witness utxo), then we're implicitly trusting the value of the txout to which the outpoint refers. Similarly we're trusting the value of the satisfaction weight since it's provided as an input to the function.
bonus:
- Conceptually how do you define an input's satisfaction weight?
ans: The satisfaction weight is the size of a fully signed input's script_sig and witness expressed in weight units - What explains the difference in satisfaction weight calculation in the
Utxo::LocalvsUtxo::Foreigncases?
ans: If the UTXO is local to the wallet, the satisfaction weight is given by the descriptor'smax_weight_to_satisfy. If we don't have the descriptor, we calculate the satisfaction weight by looking directly at the signed input using the formulaserialize(script_sig).len() * 4 + serialize(witness).len(). - What happens if a wallet's descriptor can't be "satisfied"?
ans: At present the code will panic if a descriptor can't be satisfied, although it is common for the error to be caught upstream in miniscript before a Wallet can be created.