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