Skip to content
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

tapchannel: add awareness of 1st and 2nd level HTLC sweeps to the AuxSweeper #1154

Open
wants to merge 20 commits into
base: script-key-upsert
Choose a base branch
from

Conversation

Roasbeef
Copy link
Member

In this PR, we add awareness of 1st and 2nd level HTLC sweeps to the AuxSweeper.

For 1st level sweeps (HTLC on the remote party's commitment), the logic is straight forward. We just make a new sweep desc, and create the vPkts as normal. The only new logic is that if this is an incoming HTLC success, then we'll learn the preimage after the vPkt is created. As a result, we'll need to insert the pre-image into the right location in the witness once it's known.

For 2nd level sweeps (HTLC on the local party's commitment), the logic is a bit more involved. First, we'll need to make vPkts for both the first and the second level sweeps. However we can't sign the vPKts yet (we don't have no_input), since lnd's sweeper can aggregate the HTLC sweeps, so we can only know the true outpoint once things are confirmed. In addition, we also need to insert the remote party's signature into the witness after we sign for it, using a distinct sign desc. Finally, when we go to create the anchor output for the sweeps, we must omit any second level sweeps, as the destination is already locked in by the remote party's signature.

@Roasbeef
Copy link
Member Author

Roasbeef commented Nov 9, 2024

We should merged #1184 and #1185 before this.

@Roasbeef
Copy link
Member Author

Roasbeef commented Nov 9, 2024

Will circle back to clean up the commit structure, and add more unit tests.

@guggero guggero self-requested a review November 11, 2024 12:21
Copy link
Member

@guggero guggero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a first pass to load some context.

tapchannelmsg/records.go Outdated Show resolved Hide resolved
initiator bool, htlcOutputs []*cmsg.AssetOutput, htlcAmt btcutil.Amount,
commitCsvDelay uint32, keys lnwallet.CommitmentKeyRing,
outputIndex fn.Option[uint32],
) ([]*Allocation, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: fits on previous line.

) ([]*Allocation, error) {

// TODO(roasbeef): thaw height not implemented for taproot chans rn
// (lease expiry)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not leave the code block with HasLeaseExpiration() in, so once we have a channel type that supports the lease expiry with taproot (assets) channels, this would work already? Or would there be more changes needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC the only gap to lease expiration (from the PoV of tapd) is that sometimes the settled commitment output also has a CLTV. So that should just manifest as setting the CLTV in the sweep vPkt, then generating the correct script based on the bool of if it's leased enforced or not.

ctrlBlockBytes: ctrlBlockBytes,
},
})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like something doesn't compile here (probably a rebase artifact).

@Roasbeef Roasbeef changed the base branch from main to script-key-upsert November 12, 2024 02:54
@Roasbeef
Copy link
Member Author

Pushed up a new set of commits that should compile at each point.

Next push will revise them to reduce the number, restructure, and consolidate in-PR bug fixes into their OG commit.

@coveralls
Copy link

coveralls commented Nov 12, 2024

Pull Request Test Coverage Report for Build 11809952970

Details

  • 127 of 1000 (12.7%) changed or added relevant lines in 8 files are covered.
  • 29 unchanged lines in 6 files lost coverage.
  • Overall coverage decreased (-0.4%) to 40.313%

Changes Missing Coverage Covered Lines Changed/Added Lines %
server.go 0 4 0.0%
tapdb/assets_store.go 0 4 0.0%
tapchannel/aux_leaf_signer.go 8 18 44.44%
tapchannel/aux_leaf_creator.go 0 11 0.0%
tapchannel/commitment.go 28 55 50.91%
tapchannelmsg/records.go 88 117 75.21%
tapchannel/aux_sweeper.go 0 788 0.0%
Files with Coverage Reduction New Missed Lines %
tapdb/assets_store.go 1 63.9%
tapgarden/planter.go 2 74.87%
internal/test/helpers.go 2 86.85%
tapchannel/commitment.go 3 6.76%
tapgarden/caretaker.go 4 68.87%
tapchannel/aux_sweeper.go 17 0.0%
Totals Coverage Status
Change from base Build 11789277835: -0.4%
Covered Lines: 24811
Relevant Lines: 61546

💛 - Coveralls

Copy link
Member

@GeorgeTsagk GeorgeTsagk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cACK

would be nice to have some unit coverage as well

will now work with the litd itest to understand at a better depth what exactly is going on

tapchannel/aux_sweeper.go Outdated Show resolved Hide resolved
tapchannel/aux_sweeper.go Outdated Show resolved Hide resolved
tapchannel/aux_sweeper.go Outdated Show resolved Hide resolved
tapchannel/aux_sweeper.go Outdated Show resolved Hide resolved
tapchannel/aux_sweeper.go Show resolved Hide resolved
// output, we're pretty much always able to sweep it.
//
// TODO(roasbeef): return the sats equiv budget of the asset
// amount
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdym: the guarantee of this input being swept would scale relative to the assets value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So let's say we have a 345 satoshi output, but it actually anchors $10k. We should be willing to spend up to some % of the USD value, expressed in BTC, on fees.

This current logic is a stop gap though, as we'd need to query the oracle to figure out how much the anchored asset is actually worth in BTC.

@Roasbeef Roasbeef force-pushed the htlc-resolution branch 5 times, most recently from 1435ef3 to 41f691a Compare November 13, 2024 02:51
@Roasbeef
Copy link
Member Author

Alright I've managed to chop things down from 36 to 20 commits!

This is ready for a proper pass now.

In this commit, we expand the fields of the `ContractResolution` struct
to account for second level sweeps. When we have an HTLC that needs to
go to the second level, we'll need to create 2 vPkts: one for a direct
spend from the commitment txns with the second level txn, and the other
for the spend from the sweeping transaction.

We can construct that transaction early, but can only sign for it once
we know the sweeping transaction. Therefore, we need to keep some extra
data for a given resolution, namely the tapTweak and the control block.
…kets

This'll be useful later when we need to generate the vPkt for second
level spends.
In this commit, we add two fields to the tapscriptSweepDesc struct
related to 2nd level HTLCs. First, we add the second level sig index,
which is needed to be able to know where to insert our signature after
we generate it. We also add an optional lnwallet.AuxSigDesc, which
contains the remote party's signature, and also the sighash needed for
it and a sign desc to generate it with.
In this commit, we add sweep desc generation for remote HTLCs sweeps.
This is needed when the remote party force closes, and we can spend the
HTLC directly from their commitment transaction.
In this commit, we add `blobWithWitnessInfo` which couples the raw
resolution TLV blob with some additional information such as the input
that carried the blob, and also preimage information. Preimage
information is needed to know where to insert the preimage in the
witness once we learn about it on chain.
In this commit, we update `createSweepVpackets` to be second level
aware. This means that if we detect an auxSigInfo, then we know the vPkt
we need to create is actually just the second level vPkt. We also don't
need to generate a new script key either.

Finally, we'll properly set the absolute delay if the sweep desc
indicates as such.
In this commit, we update `signSweepVpackets` to be 2nd level HTLC
aware. If we have an auxSigDesc, then that means we're spending a 2nd
level HTLC txn. To spend this properly, we'll need to insert the remote
party's signature at the proper location, as it's a 2-of-2 multi-sig.
In this commit, we make sure to pass in the correct signDesc when we go
to sign for a second level txn. For a 2nd level txn, we'll actually use
the signDesc that's needed to generate the 2-of-2 multi-sig, instead of
the one that we'd normally use to sweep.
With all the prior commits in place, we can now create the new contract
resolution that includes the 1st and 2nd level packets, and the
information that we'll need to re-sign the second level packets later.
In this commit, we add some intermediate functions and types needed to
properly handle HTLC sweeps.

We now use the preimage info added in a prior commit to make sure that
once we learn of the preimage (after vPkt creation, but before publish),
we'll properly insert it in the correct location.

In sweepContracts, when we go to create the new anchor change output,
we'll make sure to omit any second level transactions, as they already
have a destination location specified.

Direct spends are spends directly from the commitment transaction. If we
don't have any direct spends, then we don't need to make a change addr,
as second level spends are already bound to an anchor output.
In this commit, we update `registerAndBroadcastSweep` to be able to
handle HTLC sweeps.

First, we only need to set the anchor for first level sweeps.

We weren't able to sign the 2nd level sweeps earlier as we didn't know
the txid of the transaction that swept them. Now that we're about to
broadcast, we know the sweeping transaction so we can set the prevID
properly, then sign the sweeping transaction.

If the sweeper is broadcasting _just_ a second level txn with an asset,
then we won't have an extra change output. This transaction also already
has its internal key bound.
If we don't do this here, then we'll sign a second level success
transaction that doesn't have the sequence set properly. This will then
propagate all the way up to anchor output, leading to an incorrect
inclusion proof later.
In this commit, we fix an existing logic gap related to 2nd level HTLCs.
Before if we were signing a timeout for the remote party, neither of us
would properly apply the lock time to the vPkt.

In this commit, we fix it by first gaining a new `whoseCommit` param in
`FetchLeavesFromCommit`. We then use that to decide when to use a non
zero CLTV timeout.
In this commit, we fix a very subtle issue related to split witnesses
and root assets.

Before this commit, when we went to sign a second level txn, which is a
split, we would create a virtual txn, which will commit to the _entire_
witness of the root asset in the vIn. Note that this bypasses the normal
segwit encoding logic, as that currently doesn't apply to the root asset
encoded in the split commit proof.

In the future, we may want to expand the segwit encoding semantics to
root assets after careful consideration.

In this commit, we fix a bug that would cause an invalid 2nd level sig
by ensuring that before we create the output commitments, we update the
root asset witness in each split, to the funding witness script, which
is just OP_TRUE.
In this commit, we fix an issue that would cause lnd to not broadcast
sweeps of HTLCs due to their small value. Before we didn't add enough
budget to actually convince lnd to init the fee function and broadcast
the sweep.

In the future, we should do a more careful calculation here based on the
current BTC value of the asset, to make an economical decision. For now,
we just increase the amt based on the amt of inputs we have. This gives
lnd a fee budget to use for bumping.
In this commit, we update the logic of `notifyBroadcast` to use the new
`outpointToTxIndex` map. We'll use this to make sure that the vOut has
the correct anchor output index, as the sweeper applies a sorting
routine before broadcast.

Otherwise, we'll have invalid inclusion proofs.
If we don't import these script keys, spends will fail later as we
didn't credit the balance, so we can't spend them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 👀 In review
Development

Successfully merging this pull request may close these issues.

5 participants