-
Notifications
You must be signed in to change notification settings - Fork 36.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wallet: Allow users to specify input weights when funding a transaction #23201
Conversation
dc756fd
to
fd6fde8
Compare
Note that bumpfee does not take this into account yet, but it's next on my list. |
Concept ACK |
fd6fde8
to
5c2ff25
Compare
cc @t-bast maybe @apoelstra |
Concept ACK, I'll test this today with lightning transactions. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
0bada4a
to
675309b
Compare
f37d4e6
to
7121427
Compare
7121427
to
a19169a
Compare
a19169a
to
d059229
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK d059229. Here's some nits.
2996f66
to
52d8d44
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial Concept ACK, will do a more detail pass later.
Below are some minor nits (ignorable) and questions I had.
// a boundary, the size will be split so that 2/3rds will be in one stack element, and | ||
// the remaining 1/3rd in another. Using 3rds allows us to avoid additional boundaries. | ||
// 10 bytes is used because that accounts for the maximum size. This does not need to be super precise. | ||
if ((add_weight >= 253 && add_weight < 263) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming this numbers are denoting 8 bit boundaries, why its not 255 and 265?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused about this as well since I had never come across compact size uints before. It helped me to read serialize.h and about tx serialization (bip141 and this doc).
This is just saying that when the stack size goes from 252 to 253, you need more bytes to encode the size in the serialized transaction. It's not the same as a byte boundary since (I assume) you need to reserve a few values for codifying how many bytes it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK 52d8d44
Verified all tests are covering expected behavior.
Below are few non blocking nits and comments.
self.generate(self.nodes[0], 6) | ||
ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0] | ||
|
||
# An external input without solving data should result in an error | ||
assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 10 + ext_utxo['amount']}, 0, {'add_inputs': True}) | ||
assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 15}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same regarding "Insufficient funds" error here.
Is this for 0.23? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this for 0.23?
I hope so!
I've reviewed up until 8a1ea6a. I have some concerns about the argument sanitization, but otherwise looks good to me. This also needs release notes, yes?
// If available, override calculated size with coin control specified size | ||
if (coin_control.HasInputWeight(outpoint)) { | ||
input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's right. If !coin_control.GetExternalOutput, then we can't do coin selection at all and would have returned at an earlier point.
Reviewed code and I agree with this. If it's an external input, we must have not found it in mapWallet
. If we also didn't find it in GetExternalOutput()
, then we already returned nullopt
on line 461.
// a boundary, the size will be split so that 2/3rds will be in one stack element, and | ||
// the remaining 1/3rd in another. Using 3rds allows us to avoid additional boundaries. | ||
// 10 bytes is used because that accounts for the maximum size. This does not need to be super precise. | ||
if ((add_weight >= 253 && add_weight < 263) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused about this as well since I had never come across compact size uints before. It helped me to read serialize.h and about tx serialization (bip141 and this doc).
This is just saying that when the stack size goes from 252 to 253, you need more bytes to encode the size in the serialized transaction. It's not the same as a byte boundary since (I assume) you need to reserve a few values for codifying how many bytes it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reviewed the tests
a995803
to
db4efde
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK db4efde
I'm happy with FillInputToWeight()
now, thanks for addressing comments. The unit tests seem comprehensive. I tried every input from -1 to 65536 and no crashes.
Minimum input of 165 = 4 * (32 + 4 + 4 + 1) + 1 makes more sense to me than 160.
Test coverage for walletcreatefundedpsbt
, fundrawtransaction
, and send
look good to me, error messages and resulting feerates are tested and the weights used are correct now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK db4efde
In order to allow coin selection to take weights from the user, CCoinControl needs to be able to set and get them.
If the user specifies an input size, allow it to override any input size calculations during coin selection.
Coin selection requires knowing the weight of a transaction so that fees can be estimated. However for external inputs, the weight may not be avialble, and solving data may not be enough as the input could be one that we do not support. By allowing users to specify input weights, those external inputs can be included in the transaction. Additionally, if the weight for an input is specified, that value will always be used, regardless of whether the input is in the wallet or solving data is available. This allows us to account for scenarios where the wallet may be more conservative and estimate a larger input than may actually be created. For example, we assume the maximum DER signature size, but an external input may be signed by a wallet which does nonce grinding in order to get a smaller signature. In that case, the user can specify the smaller input weight to avoid overpaying transaction fees.
Added tests to rpc_fundrawtransaction, wallet_send, and rpc_psbt that test that external inputs can be spent when input weight is provided. Also tested that the input weight overrides any calculated weight. Additionally, rpc_psbt's external inputs test is cleaned up a bit to be more similar to rpc_fundrawtransaction's and avoid potential pitfalls due to non-deterministic coin selection behavior.
db4efde
to
3866272
Compare
reACK 3866272 |
@t-bast want to take another look here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 3866272
I re-run tests from a lightning node: I'm correctly able to use this new parameter to make bitcoind
fund then sign transactions that contain inputs that aren't managed by the bitcoind
wallet (in my case, HTLC outputs from a lightning commitment transaction).
A big thanks to everyone who contributed to this PR!
reACK 3866272 via range-diff Changes since last review:
|
…l inputs c3b099a wallet, tests: Test bumpfee's max input weight calculation (Andrew Chow) 116a620 Make DUMMY_CHECKER availble outside of script/sign.cpp (Andrew Chow) ff63832 test, bumpfee: Check that psbtbumpfee can bump txs with external inputs (Andrew Chow) 1bc8106 bumpfee: be able to bump fee of a tx with external inputs (Andrew Chow) 31dd3dc bumpfee: Clear scriptSigs and scriptWitnesses before calculated max size (Andrew Chow) a0c3afb bumpfee: extract weights of external inputs when bumping fee (Andrew Chow) 612f1e4 bumpfee: Calculate fee by looking up UTXOs (Andrew Chow) Pull request description: This PR allows `psbtbumpfee` to return a PSBT for transactions that contain external inputs. This does not work for bumping in the GUI nor `bumpfee` because these need private keys available to sign and send the transaction. But `psbtbumpfee` returns a psbt, so it is fine to not be able to sign. In order to correctly estimate the size of the inputs for coin selection, the fee bumper will use the size of the inputs of the transaction being bumped. Because the sizes of signatures are not guaranteed, for external inputs, the fee bumper will verify the scripts with a special SignatureChecker which will compute the weight of all of the signatures in that input, and compute their weights if those signatures were maximally sized. This allows the fee bumper to obtain a max size estimate for each external input. Builds on #23201 as it relies on the ability to pass weights in to coin selection. Closes #23189 ACKs for top commit: ishaanam: reACK c3b099a t-bast: Re-ran my tests agains c3b099a, ACK Tree-SHA512: 40016ec52d351430977579cfa2694c7e6764f42c9ce09d3a6f1753b767f86053f296d9de988248df033be6d725d67badbf2a5ef82c8ace23c61487729b7691e5
When funding a transaction with external inputs, instead of providing solving data, a user may want to just provide the maximum signed size of that input. This is particularly useful in cases where the input is nonstandard as our dummy signer is unable to handle those inputs.
The input weight can be provided to any input regardless of whether it belongs to the wallet and the provided weight will always be used regardless of any calculated input weight. This allows the user to override the calculated input weight which may overestimate in some circumstances due to missing information (e.g. if the private key is not known, a maximum size signature will be used, but the actual signer may be doing additional work which reduces the size of the signature).
For
send
andwalletcreatefundedpsbt
, the input weight is specified in aweight
field in an input object. Forfundrawtransaction
, a newinput_weights
field is added to theoptions
object. This is an array of objects consisting of a txid, vout, and weight.Closes #23187