mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
contractcourt/timeout_resolver: extract logic into sweepSecondLevelTransaction
This commit moves the logic for sweeping the confirmed second-level timeout transaction into its own method. We do a small change to the logic: When setting the spending tx in the report, we use the detected commitspend instead of the presigned tiemout tx. This is to prepare for the coming change where the spending transaction might actually be a re-signed timeout tx, and will therefore have a different txid.
This commit is contained in:
parent
2f33425509
commit
0c3b64a3cd
@ -261,8 +261,6 @@ func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
spendTxID := commitSpend.SpenderTxHash
|
|
||||||
|
|
||||||
// If the spend reveals the pre-image, then we'll enter the clean up
|
// If the spend reveals the pre-image, then we'll enter the clean up
|
||||||
// workflow to pass the pre-image back to the incoming link, add it to
|
// workflow to pass the pre-image back to the incoming link, add it to
|
||||||
// the witness cache, and exit.
|
// the witness cache, and exit.
|
||||||
@ -290,54 +288,7 @@ func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var reports []*channeldb.ResolverReport
|
return h.sweepSecondLevelTransaction(commitSpend)
|
||||||
|
|
||||||
// Finally, if this was an output on our commitment transaction, we'll
|
|
||||||
// wait for the second-level HTLC output to be spent, and for that
|
|
||||||
// transaction itself to confirm.
|
|
||||||
if h.htlcResolution.SignedTimeoutTx != nil {
|
|
||||||
log.Infof("%T(%v): waiting for nursery to spend CSV delayed "+
|
|
||||||
"output", h, h.htlcResolution.ClaimOutpoint)
|
|
||||||
sweep, err := waitForSpend(
|
|
||||||
&h.htlcResolution.ClaimOutpoint,
|
|
||||||
h.htlcResolution.SweepSignDesc.Output.PkScript,
|
|
||||||
h.broadcastHeight, h.Notifier, h.quit,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the spend txid to the hash of the sweep transaction.
|
|
||||||
spendTxID = sweep.SpenderTxHash
|
|
||||||
|
|
||||||
// Once our timeout tx has confirmed, we add a resolution for
|
|
||||||
// our timeoutTx tx first stage transaction.
|
|
||||||
timeoutTx := h.htlcResolution.SignedTimeoutTx
|
|
||||||
spendHash := timeoutTx.TxHash()
|
|
||||||
|
|
||||||
reports = append(reports, &channeldb.ResolverReport{
|
|
||||||
OutPoint: timeoutTx.TxIn[0].PreviousOutPoint,
|
|
||||||
Amount: h.htlc.Amt.ToSatoshis(),
|
|
||||||
ResolverType: channeldb.ResolverTypeOutgoingHtlc,
|
|
||||||
ResolverOutcome: channeldb.ResolverOutcomeFirstStage,
|
|
||||||
SpendTxID: &spendHash,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// With the clean up message sent, we'll now mark the contract
|
|
||||||
// resolved, record the timeout and the sweep txid on disk, and wait.
|
|
||||||
h.resolved = true
|
|
||||||
|
|
||||||
amt := btcutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value)
|
|
||||||
reports = append(reports, &channeldb.ResolverReport{
|
|
||||||
OutPoint: h.htlcResolution.ClaimOutpoint,
|
|
||||||
Amount: amt,
|
|
||||||
ResolverType: channeldb.ResolverTypeOutgoingHtlc,
|
|
||||||
ResolverOutcome: channeldb.ResolverOutcomeTimeout,
|
|
||||||
SpendTxID: spendTxID,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil, h.Checkpoint(h, reports...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// spendHtlcOutput handles the initial spend of an HTLC output via the timeout
|
// spendHtlcOutput handles the initial spend of an HTLC output via the timeout
|
||||||
@ -394,6 +345,71 @@ func (h *htlcTimeoutResolver) spendHtlcOutput() (*chainntnfs.SpendDetail, error)
|
|||||||
return spend, err
|
return spend, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sweepSecondLevelTransaction sweeps the output of the confirmed second-level
|
||||||
|
// timeout transaction into our wallet. The given SpendDetail should be the
|
||||||
|
// confirmed timeout tx spending the HTLC output on the commitment tx.
|
||||||
|
func (h *htlcTimeoutResolver) sweepSecondLevelTransaction(
|
||||||
|
commitSpend *chainntnfs.SpendDetail) (ContractResolver, error) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
// spendTxID will be the ultimate spend of the claimOutpoint.
|
||||||
|
// We set it to the commit spend for now, as this is the
|
||||||
|
// ultimate spend in case this is a remote commitment. If we go
|
||||||
|
// through the second-level transaction, we'll update this
|
||||||
|
// accordingly.
|
||||||
|
spendTxID = commitSpend.SpenderTxHash
|
||||||
|
|
||||||
|
reports []*channeldb.ResolverReport
|
||||||
|
)
|
||||||
|
|
||||||
|
// Finally, if this was an output on our commitment transaction, we'll
|
||||||
|
// wait for the second-level HTLC output to be spent, and for that
|
||||||
|
// transaction itself to confirm.
|
||||||
|
if h.htlcResolution.SignedTimeoutTx != nil {
|
||||||
|
log.Infof("%T(%v): waiting for nursery to spend CSV delayed "+
|
||||||
|
"output", h, h.htlcResolution.ClaimOutpoint)
|
||||||
|
sweep, err := waitForSpend(
|
||||||
|
&h.htlcResolution.ClaimOutpoint,
|
||||||
|
h.htlcResolution.SweepSignDesc.Output.PkScript,
|
||||||
|
h.broadcastHeight, h.Notifier, h.quit,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the spend txid to the hash of the sweep transaction.
|
||||||
|
spendTxID = sweep.SpenderTxHash
|
||||||
|
|
||||||
|
// Once our sweep of the timeout tx has confirmed, we add a
|
||||||
|
// resolution for our timeoutTx tx first stage transaction.
|
||||||
|
timeoutTx := commitSpend.SpendingTx
|
||||||
|
spendHash := timeoutTx.TxHash()
|
||||||
|
|
||||||
|
reports = append(reports, &channeldb.ResolverReport{
|
||||||
|
OutPoint: timeoutTx.TxIn[0].PreviousOutPoint,
|
||||||
|
Amount: h.htlc.Amt.ToSatoshis(),
|
||||||
|
ResolverType: channeldb.ResolverTypeOutgoingHtlc,
|
||||||
|
ResolverOutcome: channeldb.ResolverOutcomeFirstStage,
|
||||||
|
SpendTxID: &spendHash,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// With the clean up message sent, we'll now mark the contract
|
||||||
|
// resolved, record the timeout and the sweep txid on disk, and wait.
|
||||||
|
h.resolved = true
|
||||||
|
|
||||||
|
amt := btcutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value)
|
||||||
|
reports = append(reports, &channeldb.ResolverReport{
|
||||||
|
OutPoint: h.htlcResolution.ClaimOutpoint,
|
||||||
|
Amount: amt,
|
||||||
|
ResolverType: channeldb.ResolverTypeOutgoingHtlc,
|
||||||
|
ResolverOutcome: channeldb.ResolverOutcomeTimeout,
|
||||||
|
SpendTxID: spendTxID,
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil, h.Checkpoint(h, reports...)
|
||||||
|
}
|
||||||
|
|
||||||
// Stop signals the resolver to cancel any current resolution processes, and
|
// Stop signals the resolver to cancel any current resolution processes, and
|
||||||
// suspend.
|
// suspend.
|
||||||
//
|
//
|
||||||
|
@ -3,6 +3,7 @@ package contractcourt
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntest/mock"
|
"github.com/lightningnetwork/lnd/lntest/mock"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockWitnessBeacon struct {
|
type mockWitnessBeacon struct {
|
||||||
@ -127,6 +129,16 @@ func TestHtlcTimeoutResolver(t *testing.T) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To avoid triggering the race detector by
|
||||||
|
// setting the witness the second time this
|
||||||
|
// method is called during tests, we return
|
||||||
|
// immediately if the witness is already set
|
||||||
|
// correctly.
|
||||||
|
if reflect.DeepEqual(
|
||||||
|
templateTx.TxIn[0].Witness, witness,
|
||||||
|
) {
|
||||||
|
return templateTx, nil
|
||||||
|
}
|
||||||
templateTx.TxIn[0].Witness = witness
|
templateTx.TxIn[0].Witness = witness
|
||||||
return templateTx, nil
|
return templateTx, nil
|
||||||
},
|
},
|
||||||
@ -148,6 +160,17 @@ func TestHtlcTimeoutResolver(t *testing.T) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To avoid triggering the race detector by
|
||||||
|
// setting the witness the second time this
|
||||||
|
// method is called during tests, we return
|
||||||
|
// immediately if the witness is already set
|
||||||
|
// correctly.
|
||||||
|
if reflect.DeepEqual(
|
||||||
|
templateTx.TxIn[0].Witness, witness,
|
||||||
|
) {
|
||||||
|
return templateTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
templateTx.TxIn[0].Witness = witness
|
templateTx.TxIn[0].Witness = witness
|
||||||
|
|
||||||
// Set the outpoint to be on our commitment, since
|
// Set the outpoint to be on our commitment, since
|
||||||
@ -174,6 +197,17 @@ func TestHtlcTimeoutResolver(t *testing.T) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To avoid triggering the race detector by
|
||||||
|
// setting the witness the second time this
|
||||||
|
// method is called during tests, we return
|
||||||
|
// immediately if the witness is already set
|
||||||
|
// correctly.
|
||||||
|
if reflect.DeepEqual(
|
||||||
|
templateTx.TxIn[0].Witness, witness,
|
||||||
|
) {
|
||||||
|
return templateTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
templateTx.TxIn[0].Witness = witness
|
templateTx.TxIn[0].Witness = witness
|
||||||
return templateTx, nil
|
return templateTx, nil
|
||||||
},
|
},
|
||||||
@ -196,6 +230,17 @@ func TestHtlcTimeoutResolver(t *testing.T) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To avoid triggering the race detector by
|
||||||
|
// setting the witness the second time this
|
||||||
|
// method is called during tests, we return
|
||||||
|
// immediately if the witness is already set
|
||||||
|
// correctly.
|
||||||
|
if reflect.DeepEqual(
|
||||||
|
templateTx.TxIn[0].Witness, witness,
|
||||||
|
) {
|
||||||
|
return templateTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
templateTx.TxIn[0].Witness = witness
|
templateTx.TxIn[0].Witness = witness
|
||||||
return templateTx, nil
|
return templateTx, nil
|
||||||
},
|
},
|
||||||
@ -282,16 +327,19 @@ func TestHtlcTimeoutResolver(t *testing.T) {
|
|||||||
// broadcast, then we'll set the timeout commit to a fake
|
// broadcast, then we'll set the timeout commit to a fake
|
||||||
// transaction to force the code path.
|
// transaction to force the code path.
|
||||||
if !testCase.remoteCommit {
|
if !testCase.remoteCommit {
|
||||||
resolver.htlcResolution.SignedTimeoutTx = sweepTx
|
timeoutTx, err := testCase.txToBroadcast()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resolver.htlcResolution.SignedTimeoutTx = timeoutTx
|
||||||
|
|
||||||
if testCase.timeout {
|
if testCase.timeout {
|
||||||
success := sweepTx.TxHash()
|
timeoutTxID := timeoutTx.TxHash()
|
||||||
reports = append(reports, &channeldb.ResolverReport{
|
reports = append(reports, &channeldb.ResolverReport{
|
||||||
OutPoint: sweepTx.TxIn[0].PreviousOutPoint,
|
OutPoint: timeoutTx.TxIn[0].PreviousOutPoint,
|
||||||
Amount: testHtlcAmt.ToSatoshis(),
|
Amount: testHtlcAmt.ToSatoshis(),
|
||||||
ResolverType: channeldb.ResolverTypeOutgoingHtlc,
|
ResolverType: channeldb.ResolverTypeOutgoingHtlc,
|
||||||
ResolverOutcome: channeldb.ResolverOutcomeFirstStage,
|
ResolverOutcome: channeldb.ResolverOutcomeFirstStage,
|
||||||
SpendTxID: &success,
|
SpendTxID: &timeoutTxID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user