mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-13 11:09:23 +01:00
contractcourt: update htlcSuccessResolver for taproot chans
This commit is contained in:
parent
23f7ee39c7
commit
df2a2d83ea
2 changed files with 91 additions and 29 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||
|
@ -103,9 +104,9 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
|
|||
|
||||
// If we've locked in an htlc with an invalid payload on our
|
||||
// commitment tx, we don't need to resolve it. The other party
|
||||
// will time it out and get their funds back. This situation can
|
||||
// present itself when we crash before processRemoteAdds in the
|
||||
// link has ran.
|
||||
// will time it out and get their funds back. This situation
|
||||
// can present itself when we crash before processRemoteAdds in
|
||||
// the link has ran.
|
||||
h.resolved = true
|
||||
|
||||
if err := h.processFinalHtlcFail(); err != nil {
|
||||
|
@ -192,17 +193,41 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
|
|||
log.Infof("%T(%v): applied preimage=%v", h,
|
||||
h.htlcResolution.ClaimOutpoint, preimage)
|
||||
|
||||
isSecondLevel := h.htlcResolution.SignedSuccessTx != nil
|
||||
|
||||
// If we didn't have to go to the second level to claim (this
|
||||
// is the remote commitment transaction), then we don't need to
|
||||
// modify our canned witness.
|
||||
if !isSecondLevel {
|
||||
return nil
|
||||
}
|
||||
|
||||
isTaproot := txscript.IsPayToTaproot(
|
||||
h.htlcResolution.SignedSuccessTx.TxOut[0].PkScript,
|
||||
)
|
||||
|
||||
// If this is our commitment transaction, then we'll need to
|
||||
// populate the witness for the second-level HTLC transaction.
|
||||
if h.htlcResolution.SignedSuccessTx != nil {
|
||||
// Within the witness for the success transaction, the
|
||||
// preimage is the 4th element as it looks like:
|
||||
//
|
||||
// * <sender sig> <recvr sig> <preimage> <witness script>
|
||||
//
|
||||
// We'll populate it within the witness, as since this
|
||||
// was a "contest" resolver, we didn't yet know of the
|
||||
// preimage.
|
||||
switch {
|
||||
// For taproot channels, the witness for sweeping with sucess
|
||||
// looks like:
|
||||
// - <sender sig> <receiver sig> <preimage> <success_script>
|
||||
// <control_block>
|
||||
//
|
||||
// So we'll insert it at the 3rd index of the witness.
|
||||
case isTaproot:
|
||||
//nolint:lll
|
||||
h.htlcResolution.SignedSuccessTx.TxIn[0].Witness[2] = preimage[:]
|
||||
|
||||
// Within the witness for the success transaction, the
|
||||
// preimage is the 4th element as it looks like:
|
||||
//
|
||||
// * <0> <sender sig> <recvr sig> <preimage> <witness script>
|
||||
//
|
||||
// We'll populate it within the witness, as since this
|
||||
// was a "contest" resolver, we didn't yet know of the
|
||||
// preimage.
|
||||
case !isTaproot:
|
||||
h.htlcResolution.SignedSuccessTx.TxIn[0].Witness[3] = preimage[:]
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
|
@ -14,6 +15,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/channeldb/models"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/labels"
|
||||
"github.com/lightningnetwork/lnd/lnutils"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/sweep"
|
||||
)
|
||||
|
@ -171,9 +173,9 @@ func (h *htlcSuccessResolver) broadcastSuccessTx() (*wire.OutPoint, error) {
|
|||
// If we have non-nil SignDetails, this means that have a 2nd level
|
||||
// HTLC transaction that is signed using sighash SINGLE|ANYONECANPAY
|
||||
// (the case for anchor type channels). In this case we can re-sign it
|
||||
// and attach fees at will. We let the sweeper handle this job.
|
||||
// We use the checkpointed outputIncubating field to determine if we
|
||||
// already swept the HTLC output into the second level transaction.
|
||||
// and attach fees at will. We let the sweeper handle this job. We use
|
||||
// the checkpointed outputIncubating field to determine if we already
|
||||
// swept the HTLC output into the second level transaction.
|
||||
if h.htlcResolution.SignDetails != nil {
|
||||
return h.broadcastReSignedSuccessTx()
|
||||
}
|
||||
|
@ -233,16 +235,29 @@ func (h *htlcSuccessResolver) broadcastReSignedSuccessTx() (
|
|||
|
||||
// We will have to let the sweeper re-sign the success tx and wait for
|
||||
// it to confirm, if we haven't already.
|
||||
isTaproot := txscript.IsPayToTaproot(
|
||||
h.htlcResolution.SweepSignDesc.Output.PkScript,
|
||||
)
|
||||
if !h.outputIncubating {
|
||||
log.Infof("%T(%x): offering second-layer transition tx to "+
|
||||
"sweeper: %v", h, h.htlc.RHash[:],
|
||||
spew.Sdump(h.htlcResolution.SignedSuccessTx))
|
||||
|
||||
secondLevelInput := input.MakeHtlcSecondLevelSuccessAnchorInput(
|
||||
h.htlcResolution.SignedSuccessTx,
|
||||
h.htlcResolution.SignDetails, h.htlcResolution.Preimage,
|
||||
h.broadcastHeight,
|
||||
)
|
||||
var secondLevelInput input.HtlcSecondLevelAnchorInput
|
||||
if isTaproot {
|
||||
secondLevelInput = input.MakeHtlcSecondLevelSuccessTaprootInput(
|
||||
h.htlcResolution.SignedSuccessTx,
|
||||
h.htlcResolution.SignDetails, h.htlcResolution.Preimage,
|
||||
h.broadcastHeight,
|
||||
)
|
||||
} else {
|
||||
secondLevelInput = input.MakeHtlcSecondLevelSuccessAnchorInput(
|
||||
h.htlcResolution.SignedSuccessTx,
|
||||
h.htlcResolution.SignDetails, h.htlcResolution.Preimage,
|
||||
h.broadcastHeight,
|
||||
)
|
||||
}
|
||||
|
||||
_, err := h.Sweeper.SweepInput(
|
||||
&secondLevelInput,
|
||||
sweep.Params{
|
||||
|
@ -341,13 +356,20 @@ func (h *htlcSuccessResolver) broadcastReSignedSuccessTx() (
|
|||
|
||||
// Let the sweeper sweep the second-level output now that the
|
||||
// CSV/CLTV locks have expired.
|
||||
var witType input.StandardWitnessType
|
||||
if isTaproot {
|
||||
witType = input.TaprootHtlcAcceptedSuccessSecondLevel
|
||||
} else {
|
||||
witType = input.HtlcAcceptedSuccessSecondLevel
|
||||
}
|
||||
inp := h.makeSweepInput(
|
||||
op, input.HtlcAcceptedSuccessSecondLevel,
|
||||
op, witType,
|
||||
input.LeaseHtlcAcceptedSuccessSecondLevel,
|
||||
&h.htlcResolution.SweepSignDesc,
|
||||
h.htlcResolution.CsvDelay, h.broadcastHeight,
|
||||
h.htlc.RHash,
|
||||
)
|
||||
// TODO(roasbeef): need to update above for leased types
|
||||
_, err = h.Sweeper.SweepInput(
|
||||
inp,
|
||||
sweep.Params{
|
||||
|
@ -377,17 +399,32 @@ func (h *htlcSuccessResolver) resolveRemoteCommitOutput() (
|
|||
log.Infof("%T(%x): crafting sweep tx for incoming+remote "+
|
||||
"htlc confirmed", h, h.htlc.RHash[:])
|
||||
|
||||
isTaproot := txscript.IsPayToTaproot(
|
||||
h.htlcResolution.SweepSignDesc.Output.PkScript,
|
||||
)
|
||||
|
||||
// Before we can craft out sweeping transaction, we need to
|
||||
// create an input which contains all the items required to add
|
||||
// this input to a sweeping transaction, and generate a
|
||||
// witness.
|
||||
inp := input.MakeHtlcSucceedInput(
|
||||
&h.htlcResolution.ClaimOutpoint,
|
||||
&h.htlcResolution.SweepSignDesc,
|
||||
h.htlcResolution.Preimage[:],
|
||||
h.broadcastHeight,
|
||||
h.htlcResolution.CsvDelay,
|
||||
)
|
||||
var inp input.Input
|
||||
if isTaproot {
|
||||
inp = lnutils.Ptr(input.MakeTaprootHtlcSucceedInput(
|
||||
&h.htlcResolution.ClaimOutpoint,
|
||||
&h.htlcResolution.SweepSignDesc,
|
||||
h.htlcResolution.Preimage[:],
|
||||
h.broadcastHeight,
|
||||
h.htlcResolution.CsvDelay,
|
||||
))
|
||||
} else {
|
||||
inp = lnutils.Ptr(input.MakeHtlcSucceedInput(
|
||||
&h.htlcResolution.ClaimOutpoint,
|
||||
&h.htlcResolution.SweepSignDesc,
|
||||
h.htlcResolution.Preimage[:],
|
||||
h.broadcastHeight,
|
||||
h.htlcResolution.CsvDelay,
|
||||
))
|
||||
}
|
||||
|
||||
// With the input created, we can now generate the full sweep
|
||||
// transaction, that we'll use to move these coins back into
|
||||
|
@ -400,7 +437,7 @@ func (h *htlcSuccessResolver) resolveRemoteCommitOutput() (
|
|||
// TODO: Use time-based sweeper and result chan.
|
||||
var err error
|
||||
h.sweepTx, err = h.Sweeper.CreateSweepTx(
|
||||
[]input.Input{&inp},
|
||||
[]input.Input{inp},
|
||||
sweep.FeePreference{
|
||||
ConfTarget: sweepConfTarget,
|
||||
}, 0,
|
||||
|
|
Loading…
Add table
Reference in a new issue