-
Notifications
You must be signed in to change notification settings - Fork 116
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
sweepbatcher: add mixed batches as an option #791
sweepbatcher: add mixed batches as an option #791
Conversation
cce93ad
to
9b82990
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.
I appreciate your effort towards more flexible batcher features. On my first pass I just have a question regarding the leafWitnessSize
. Great catch btw 🥇
@@ -962,21 +962,21 @@ func (b *batch) debugLogTx(msg string, tx *wire.MsgTx) { | |||
|
|||
// coopSignBatchTx collects the necessary signatures from the server in order | |||
// to cooperatively sweep the funds. | |||
func (b *batch) coopSignBatchTx(ctx context.Context, packet *psbt.Packet, | |||
func (b *batch) coopSignBatchTx(ctx context.Context, tx *wire.MsgTx, |
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.
👌
var psbtBuf bytes.Buffer | ||
err = packet.Serialize(&psbtBuf) | ||
// Create PSBT and prevOuts. | ||
psbtBytes, prevOuts, err := b.createPsbt(batchTx, sweeps) |
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.
👌
swap/htlc.go
Outdated
@@ -283,10 +281,20 @@ func (h *Htlc) AddSuccessToEstimator(estimator *input.TxWeightEstimator) error { | |||
trHtlc.InternalPubKey, successLeaf, timeoutLeafHash[:], | |||
) | |||
|
|||
estimator.AddTapscriptInput(maxSuccessWitnessSize, tapscript) | |||
// The leaf witness size must be calculated without the byte |
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.
that's a very good catch fixing the fee overpayment 🥇
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.
The godoc says only the total size of all elements on the stack that are consumed by the revealed script should be counted.
but we also count sigLength
and preimg_length
which I am unsure if they are pushed to the stack? I tought just the sig and the preimage are pushed?
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.
IIUC, sizes of elements also consume space in encoded transaction, even though they are not themselves pushed to stack. In sweepbatcher, I added comparison of real tx weight and the estimated weight, logging a warning in case of a discrepancy. The current value of leafWitnessSize
(with elements' sizes) results in weight estimates equal to real tx size.
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.
Oh that's a very nice catch!
9b82990
to
2364192
Compare
Converting to draft for now. Changes are needed in greedy batch selection algorithm, to adjust to the fact that batches can be mixed 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.
Really nice work!! 🎉 Just a few comments, but overall looks very good already!
swap/htlc.go
Outdated
@@ -283,10 +281,20 @@ func (h *Htlc) AddSuccessToEstimator(estimator *input.TxWeightEstimator) error { | |||
trHtlc.InternalPubKey, successLeaf, timeoutLeafHash[:], | |||
) | |||
|
|||
estimator.AddTapscriptInput(maxSuccessWitnessSize, tapscript) | |||
// The leaf witness size must be calculated without the byte |
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.
Oh that's a very nice catch!
sweepbatcher/sweep_batch.go
Outdated
if ok { | ||
// Preserve coopFailed value not to forget about cooperative | ||
// spending failure in this sweep. | ||
sweepValue := *sweep |
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.
nit: i think naming this variable as tmp
could be more readable.
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.
Done.
sweepbatcher/sweep_batch.go
Outdated
if err != nil { | ||
b.log.Warnf("Mixed batch publish error: %v", err) | ||
} else { | ||
coopSuccess = true |
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.
Would this fail if it fails to replace the tx in the mempool?
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 changed publishMixedBatch
interface: now it returns signSuccess bool
result, as well as publishBatchCoop
function. Also I renamed coopSuccess
local variable here to signSuccess
, since it indicates success of signing (and all preceding actions), which may be fully non-cooperative in case of publishMixedBatch
.
sweepbatcher/sweep_batch.go
Outdated
txHash := tx.TxHash() | ||
b.log.Infof("attempting to publish mixed tx=%v with feerate=%v, "+ | ||
"weight=%v, feeForWeight=%v, fee=%v, sweeps=%d (%d cooperative"+ | ||
" + %d non-cooperative), destAddr=%s", |
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.
nit: Would be nice to also log the swap hashes for additional debug info.
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.
Done. Now log lines look like this:
attempting to publish mixed tx=xxx with feerate=10000 sat/kw, weight=559 wu, feeForWeight=0.00005590 BTC, fee=0.00005590 BTC, sweeps=1, 0 cooperative: () and 1 non-cooperative (01d0fabd251f), destAddr=xxx
attempting to publish mixed tx=xxxx with feerate=10000 sat/kw, weight=3377 wu, feeForWeight=0.00033770 BTC, fee=0.00033770 BTC, sweeps=9, 2 cooperative: (938834d6c636, 34ec81dbdaf9) and 7 non-cooperative (01d0fabd251f, 5778f985db75, 91d3827f052f, 4b78063b9c22, f5411ec7e51e, aae761377f3b, 067dc6a81018), destAddr=xxx
err := b.wallet.PublishTransaction( | ||
ctx, tx, labels.LoopOutBatchSweepSuccess(b.id), | ||
) | ||
if err != nil { |
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.
Ideally I think we'd want to filter out the case where replace fails (but the tx itself is valid) so we don't end up ditching the coops sweeps in favor of revealing the scripts etc.
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.
Done. See the comment above, about "signSuccess".
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 think this requires checking for publishing errors like output already spent
I think.
Discussed offline.
1be3a90
to
3d26a70
Compare
Updated greedy batch selection algorithm to take into account whether mixed batches are enabled! |
@bhandras: review reminder |
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.
LGTM, awesome work! 🎉
3d26a70
to
59911be
Compare
Rebased. Removed the commit already merged in #804 |
NB: after #809 is merged, the custom transaction label generator should be used in mixed batch code as well. |
59911be
to
f21ec9a
Compare
Rebased |
Pushed a fix for signing code. Real SignOutputRaw requires prevOuts for all inputs, not only the ones being signed. The commit will be squashed later. |
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.
Great work and nice test coverage to back it up, including the integration test.
// mixedBatch instructs sweepbatcher to create mixed batches with regard | ||
// to cooperativeness. Such a batch can include sweeps signed both | ||
// cooperatively and non-cooperatively. If cooperative signing fails for | ||
// a sweep, transaction is updated to sign that sweep non-cooperatively |
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.
really cool system 👌
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.
Thanks! 😎
func (b *batch) constructUnsignedTx(sweeps []sweep, | ||
address btcutil.Address) (*wire.MsgTx, lntypes.WeightUnit, | ||
btcutil.Amount, btcutil.Amount, error) { | ||
|
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.
nit: could return early if sweeps
is empty.
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.
Done
sweepbatcher/sweep_batch.go
Outdated
false | ||
} | ||
|
||
// Keep track of if any new sweep failed to sign cooperatively. |
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.
nit: Keep track if any...
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.
Fixed
} | ||
|
||
// Publish the transaction. | ||
err := b.wallet.PublishTransaction( |
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.
nit:
label := labels.LoopOutBatchSweepSuccess(b.id)
err := b.wallet.PublishTransaction(ctx, tx, label)
if err != nil {
return 0, fmt.Errorf("publishing tx failed: %w", err), true
}
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.
It should be b.cfg.txLabeler(b.id)
, not labels.LoopOutBatchSweepSuccess(b.id)
, see #809
err := b.wallet.PublishTransaction( | ||
ctx, tx, labels.LoopOutBatchSweepSuccess(b.id), | ||
) | ||
if err != nil { |
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 think this requires checking for publishing errors like output already spent
I think.
Discussed offline.
fcc5d41
to
2e27f4c
Compare
... instead of psbt.Packet. Make the code simpler. Function worked with packet.UnsignedTx only, so it is easier to pass tx directly.
Unload method publishBatchCoop. Also this code will be reused in new method for mixed batches soon.
Size of a signature affects the weight of transaction, which is verified in tests. Also method SignOutputRaw now returns the number of signatures matching the number of signature descriptors to prevent crashes in tests where multiple inputs are signed.
Option WithMixedBatch instructs sweepbatcher to create mixed batches with regard to cooperativeness. Such a batch can include both sweeps signed both cooperatively and non-cooperatively. If cooperative signing fails for a sweep, transaction is updated to sign that sweep non-cooperatively and another round of cooperative signing runs on the remaining sweeps. The remaining sweeps are signed in non-cooperative (more expensive) way. If the whole procedure fails for whatever reason, the batch is signed non-cooperatively (the fallback).
Treat coopFailed flag the same as nonCoopHint. The former is what we found in previos signing attempts, the later is what the caller signalled to us.
2e27f4c
to
b171f76
Compare
Option
WithMixedBatch
instructssweepbatcher
to create mixed batches with regard to cooperativeness. Such a batch can include both sweeps signed both cooperatively and non-cooperatively. If cooperative signing fails for a sweep, transaction is updated to sign that sweep non-cooperatively and another round of cooperative signing runs on the remaining sweeps. The remaining sweeps are signed in non-cooperative (more expensive) way. If the whole procedure fails for whatever reason, the batch is signed non-cooperatively (the fallback).Updated greedy batch selection algorithm to take into account whether mixed batches are enabled.
Pull Request Checklist
release_notes.md
if your PR contains major features, breaking changes or bugfixes