2022-06-01 01:53:06 +02:00
|
|
|
package contractcourt
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2024-10-16 04:36:11 +02:00
|
|
|
"github.com/lightningnetwork/lnd/fn"
|
2022-06-01 01:53:06 +02:00
|
|
|
"github.com/lightningnetwork/lnd/input"
|
2024-10-16 04:36:11 +02:00
|
|
|
"github.com/lightningnetwork/lnd/tlv"
|
2022-06-01 01:53:06 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// htlcLeaseResolver is a struct that houses the lease specific HTLC resolution
|
|
|
|
// logic. This includes deriving the _true_ waiting height, as well as the
|
|
|
|
// input to offer to the sweeper.
|
|
|
|
type htlcLeaseResolver struct {
|
|
|
|
// channelInitiator denotes whether the party responsible for resolving
|
|
|
|
// the contract initiated the channel.
|
|
|
|
channelInitiator bool
|
|
|
|
|
|
|
|
// leaseExpiry denotes the additional waiting period the contract must
|
|
|
|
// hold until it can be resolved. This waiting period is known as the
|
|
|
|
// expiration of a script-enforced leased channel and only applies to
|
|
|
|
// the channel initiator.
|
|
|
|
//
|
|
|
|
// NOTE: This value should only be set when the contract belongs to a
|
|
|
|
// leased channel.
|
|
|
|
leaseExpiry uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// hasCLTV denotes whether the resolver must wait for an additional CLTV to
|
|
|
|
// expire before resolving the contract.
|
|
|
|
func (h *htlcLeaseResolver) hasCLTV() bool {
|
|
|
|
return h.channelInitiator && h.leaseExpiry > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// deriveWaitHeight computes the height the resolver needs to wait until it can
|
|
|
|
// sweep the input.
|
|
|
|
func (h *htlcLeaseResolver) deriveWaitHeight(csvDelay uint32,
|
|
|
|
commitSpend *chainntnfs.SpendDetail) uint32 {
|
|
|
|
|
|
|
|
waitHeight := uint32(commitSpend.SpendingHeight) + csvDelay - 1
|
|
|
|
if h.hasCLTV() {
|
|
|
|
waitHeight = uint32(math.Max(
|
|
|
|
float64(waitHeight), float64(h.leaseExpiry),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
return waitHeight
|
|
|
|
}
|
|
|
|
|
|
|
|
// makeSweepInput constructs the type of input (either just csv or csv+ctlv) to
|
|
|
|
// send to the sweeper so the output can ultimately be swept.
|
|
|
|
func (h *htlcLeaseResolver) makeSweepInput(op *wire.OutPoint,
|
|
|
|
wType, cltvWtype input.StandardWitnessType,
|
2024-10-16 04:36:11 +02:00
|
|
|
signDesc *input.SignDescriptor, csvDelay, broadcastHeight uint32,
|
|
|
|
payHash [32]byte, resBlob fn.Option[tlv.Blob]) *input.BaseInput {
|
2022-06-01 01:53:06 +02:00
|
|
|
|
|
|
|
if h.hasCLTV() {
|
|
|
|
log.Infof("%T(%x): CSV and CLTV locks expired, offering "+
|
|
|
|
"second-layer output to sweeper: %v", h, payHash, op)
|
|
|
|
|
|
|
|
return input.NewCsvInputWithCltv(
|
|
|
|
op, cltvWtype, signDesc,
|
|
|
|
broadcastHeight, csvDelay,
|
|
|
|
h.leaseExpiry,
|
2024-10-16 04:36:11 +02:00
|
|
|
input.WithResolutionBlob(resBlob),
|
2022-06-01 01:53:06 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("%T(%x): CSV lock expired, offering second-layer output to "+
|
|
|
|
"sweeper: %v", h, payHash, op)
|
|
|
|
|
2024-10-16 04:36:11 +02:00
|
|
|
return input.NewCsvInput(
|
|
|
|
op, wType, signDesc, broadcastHeight, csvDelay,
|
|
|
|
input.WithResolutionBlob(resBlob),
|
|
|
|
)
|
2022-06-01 01:53:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// SupplementState allows the user of a ContractResolver to supplement it with
|
|
|
|
// state required for the proper resolution of a contract.
|
|
|
|
//
|
|
|
|
// NOTE: Part of the ContractResolver interface.
|
|
|
|
func (h *htlcLeaseResolver) SupplementState(state *channeldb.OpenChannel) {
|
|
|
|
if state.ChanType.HasLeaseExpiration() {
|
|
|
|
h.leaseExpiry = state.ThawHeight
|
|
|
|
}
|
|
|
|
h.channelInitiator = state.IsInitiator
|
|
|
|
}
|