contractcourt+lnd: make IncubateOutputs take fn.Option

`IncubateOutputs` never takes more than one HTLC, so we change the
params to be optional, which helps with the following commit where we
pass the deadline height when incubating outgoing HTLCs.
This commit is contained in:
yyforyongyu 2024-03-29 23:44:59 +08:00
parent 6f0c2b5bab
commit 33abbe1942
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868
9 changed files with 44 additions and 40 deletions

View File

@ -114,14 +114,15 @@ type ChainArbitratorConfig struct {
// returned.
IsOurAddress func(btcutil.Address) bool
// IncubateOutput sends either an incoming HTLC, an outgoing HTLC, or
// IncubateOutputs sends either an incoming HTLC, an outgoing HTLC, or
// both to the utxo nursery. Once this function returns, the nursery
// should have safely persisted the outputs to disk, and should start
// the process of incubation. This is used when a resolver wishes to
// pass off the output to the nursery as we're only waiting on an
// absolute/relative item block.
IncubateOutputs func(wire.OutPoint, *lnwallet.OutgoingHtlcResolution,
*lnwallet.IncomingHtlcResolution, uint32) error
IncubateOutputs func(wire.OutPoint,
fn.Option[lnwallet.OutgoingHtlcResolution],
fn.Option[lnwallet.IncomingHtlcResolution], uint32) error
// PreimageDB is a global store of all known pre-images. We'll use this
// to decide if we should broadcast a commitment transaction to claim

View File

@ -362,8 +362,9 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog,
ConfChan: make(chan *chainntnfs.TxConfirmation),
},
IncubateOutputs: func(wire.OutPoint,
*lnwallet.OutgoingHtlcResolution,
*lnwallet.IncomingHtlcResolution, uint32) error {
fn.Option[lnwallet.OutgoingHtlcResolution],
fn.Option[lnwallet.IncomingHtlcResolution],
uint32) error {
incubateChan <- struct{}{}
return nil

View File

@ -206,7 +206,8 @@ func (h *htlcSuccessResolver) broadcastSuccessTx() (*wire.OutPoint, error) {
h, h.htlc.RHash[:])
err := h.IncubateOutputs(
h.ChanPoint, nil, &h.htlcResolution,
h.ChanPoint, fn.None[lnwallet.OutgoingHtlcResolution](),
fn.Some(h.htlcResolution),
h.broadcastHeight,
)
if err != nil {

View File

@ -12,6 +12,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnmock"
@ -65,8 +66,10 @@ func newHtlcResolverTestContext(t *testing.T,
return nil
},
Sweeper: newMockSweeper(),
IncubateOutputs: func(wire.OutPoint, *lnwallet.OutgoingHtlcResolution,
*lnwallet.IncomingHtlcResolution, uint32) error {
IncubateOutputs: func(wire.OutPoint,
fn.Option[lnwallet.OutgoingHtlcResolution],
fn.Option[lnwallet.IncomingHtlcResolution],
uint32) error {
return nil
},

View File

@ -545,7 +545,8 @@ func (h *htlcTimeoutResolver) sendSecondLevelTxLegacy() error {
h.htlcResolution.ClaimOutpoint)
err := h.IncubateOutputs(
h.ChanPoint, &h.htlcResolution, nil,
h.ChanPoint, fn.Some(h.htlcResolution),
fn.None[lnwallet.IncomingHtlcResolution](),
h.broadcastHeight,
)
if err != nil {

View File

@ -14,6 +14,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/htlcswitch/hop"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/kvdb"
@ -279,13 +280,14 @@ func TestHtlcTimeoutResolver(t *testing.T) {
resolutionChan := make(chan ResolutionMsg, 1)
reportChan := make(chan *channeldb.ResolverReport)
//nolint:lll
chainCfg := ChannelArbitratorConfig{
ChainArbitratorConfig: ChainArbitratorConfig{
Notifier: notifier,
PreimageDB: witnessBeacon,
IncubateOutputs: func(wire.OutPoint,
*lnwallet.OutgoingHtlcResolution,
*lnwallet.IncomingHtlcResolution,
fn.Option[lnwallet.OutgoingHtlcResolution],
fn.Option[lnwallet.IncomingHtlcResolution],
uint32) error {
incubateChan <- struct{}{}

View File

@ -15,6 +15,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/labels"
"github.com/lightningnetwork/lnd/lnwallet"
@ -333,8 +334,8 @@ func (u *UtxoNursery) Stop() error {
// they're CLTV absolute time locked, or if they're CSV relative time locked.
// Once all outputs reach maturity, they'll be swept back into the wallet.
func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
outgoingHtlcs []lnwallet.OutgoingHtlcResolution,
incomingHtlcs []lnwallet.IncomingHtlcResolution,
outgoingHtlc fn.Option[lnwallet.OutgoingHtlcResolution],
incomingHtlc fn.Option[lnwallet.IncomingHtlcResolution],
broadcastHeight uint32) error {
// Add to wait group because nursery might shut down during execution of
@ -352,14 +353,13 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
default:
}
numHtlcs := len(incomingHtlcs) + len(outgoingHtlcs)
var (
// Kid outputs can be swept after an initial confirmation
// followed by a maturity period.Baby outputs are two stage and
// will need to wait for an absolute time out to reach a
// confirmation, then require a relative confirmation delay.
kidOutputs = make([]kidOutput, 0, 1+len(incomingHtlcs))
babyOutputs = make([]babyOutput, 0, len(outgoingHtlcs))
kidOutputs = make([]kidOutput, 0)
babyOutputs = make([]babyOutput, 0)
)
// 1. Build all the spendable outputs that we will try to incubate.
@ -369,7 +369,7 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
// For each incoming HTLC, we'll register a kid output marked as a
// second-layer HTLC output. We effectively skip the baby stage (as the
// timelock is zero), and enter the kid stage.
for _, htlcRes := range incomingHtlcs {
incomingHtlc.WhenSome(func(htlcRes lnwallet.IncomingHtlcResolution) {
// Based on the input pk script of the sign descriptor, we can
// determine if this is a taproot output or not. This'll
// determine the witness type we try to set below.
@ -392,13 +392,13 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
if htlcOutput.Amount() > 0 {
kidOutputs = append(kidOutputs, htlcOutput)
}
}
})
// For each outgoing HTLC, we'll create a baby output. If this is our
// commitment transaction, then we'll broadcast a second-layer
// transaction to transition to a kid output. Otherwise, we'll directly
// spend once the CLTV delay us up.
for _, htlcRes := range outgoingHtlcs {
outgoingHtlc.WhenSome(func(htlcRes lnwallet.OutgoingHtlcResolution) {
// If this HTLC is on our commitment transaction, then it'll be
// a baby output as we need to go to the second level to sweep
// it.
@ -408,7 +408,8 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
if htlcOutput.Amount() > 0 {
babyOutputs = append(babyOutputs, htlcOutput)
}
continue
return
}
// Based on the input pk script of the sign descriptor, we can
@ -435,12 +436,13 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint,
witType, &htlcRes.SweepSignDesc, htlcRes.Expiry,
)
kidOutputs = append(kidOutputs, htlcOutput)
}
})
// TODO(roasbeef): if want to handle outgoing on remote commit
// * need ability to cancel in the case that we learn of pre-image or
// remote party pulls
numHtlcs := len(babyOutputs) + len(kidOutputs)
utxnLog.Infof("Incubating Channel(%s) num-htlcs=%d",
chanPoint, numHtlcs)

View File

@ -16,7 +16,9 @@ import (
"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/channeldb"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lntest/mock"
"github.com/lightningnetwork/lnd/lnwallet"
@ -627,8 +629,8 @@ func incubateTestOutput(t *testing.T, nursery *UtxoNursery,
// Hand off to nursery.
err := nursery.IncubateOutputs(
testChanPoint,
[]lnwallet.OutgoingHtlcResolution{*outgoingRes},
nil, 0,
fn.Some(*outgoingRes),
fn.None[lnwallet.IncomingHtlcResolution](), 0,
)
if err != nil {
t.Fatal(err)
@ -709,8 +711,8 @@ func TestRejectedCribTransaction(t *testing.T) {
// Hand off to nursery.
err := ctx.nursery.IncubateOutputs(
testChanPoint,
[]lnwallet.OutgoingHtlcResolution{*outgoingRes},
nil, 0,
fn.Some(*outgoingRes),
fn.None[lnwallet.IncomingHtlcResolution](), 0,
)
if test.expectErr {
require.ErrorIs(t, err, test.broadcastErr)
@ -758,7 +760,8 @@ func assertNurseryReport(t *testing.T, nursery *UtxoNursery,
if len(report.Htlcs) != expectedNofHtlcs {
t.Fatalf("expected %v outputs to be reported, but report "+
"only contains %v", expectedNofHtlcs, len(report.Htlcs))
"contains %s", expectedNofHtlcs,
spew.Sdump(report.Htlcs))
}
if expectedNofHtlcs != 0 {

View File

@ -38,6 +38,7 @@ import (
"github.com/lightningnetwork/lnd/contractcourt"
"github.com/lightningnetwork/lnd/discovery"
"github.com/lightningnetwork/lnd/feature"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/healthcheck"
"github.com/lightningnetwork/lnd/htlcswitch"
@ -1148,23 +1149,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
return nil
},
IncubateOutputs: func(chanPoint wire.OutPoint,
outHtlcRes *lnwallet.OutgoingHtlcResolution,
inHtlcRes *lnwallet.IncomingHtlcResolution,
outHtlcRes fn.Option[lnwallet.OutgoingHtlcResolution],
inHtlcRes fn.Option[lnwallet.IncomingHtlcResolution],
broadcastHeight uint32) error {
var (
inRes []lnwallet.IncomingHtlcResolution
outRes []lnwallet.OutgoingHtlcResolution
)
if inHtlcRes != nil {
inRes = append(inRes, *inHtlcRes)
}
if outHtlcRes != nil {
outRes = append(outRes, *outHtlcRes)
}
return s.utxoNursery.IncubateOutputs(
chanPoint, outRes, inRes,
chanPoint, outHtlcRes, inHtlcRes,
broadcastHeight,
)
},