lnwallet: add field CommitTxBlockHeight to ResolutionReq

Introduce `CommitTxBlockHeight` field to the `ResolutionReq` structure
and related methods. This field records the block height where a
commitment transaction has confirmed.
This commit is contained in:
ffranr committed 2025-11-25 17:06:18 +00:00
1 parent b9ea7070c2
commit 3d2b0d703e
3 files changed
+58 -31

No files matched your search

+2 -1
View File
@@ -1061,7 +1061,8 @@ func (c *chainWatcher) dispatchLocalForceClose(
"detected", c.cfg.chanState.FundingOutpoint) "detected", c.cfg.chanState.FundingOutpoint)
forceClose, err := lnwallet.NewLocalForceCloseSummary( forceClose, err := lnwallet.NewLocalForceCloseSummary(
c.cfg.chanState, c.cfg.signer, commitSpend.SpendingTx, stateNum, c.cfg.chanState, c.cfg.signer, commitSpend.SpendingTx,
uint32(commitSpend.SpendingHeight), stateNum,
c.cfg.auxLeafStore, c.cfg.auxResolver, c.cfg.auxLeafStore, c.cfg.auxResolver,
) )
if err != nil { if err != nil {
+4
View File
@@ -77,6 +77,10 @@ type ResolutionReq struct {
// CommitTx is the force close commitment transaction. // CommitTx is the force close commitment transaction.
CommitTx *wire.MsgTx CommitTx *wire.MsgTx
// CommitTxBlockHeight is the block height where the commitment
// transaction confirmed. It is 0 if unknown or not confirmed yet.
CommitTxBlockHeight uint32
// CommitFee is the fee that was paid for the commitment transaction. // CommitFee is the fee that was paid for the commitment transaction.
CommitFee btcutil.Amount CommitFee btcutil.Amount
+52 -30
View File
@@ -2215,6 +2215,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// At this point, we'll check to see if we need any extra // At this point, we'll check to see if we need any extra
// resolution data for this output. // resolution data for this output.
//
//nolint:ll
resolveReq := ResolutionReq{ resolveReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanState.ChanType, ChanType: chanState.ChanType,
@@ -2224,6 +2226,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
Type: input.TaprootRemoteCommitSpend, Type: input.TaprootRemoteCommitSpend,
CloseType: Breach, CloseType: Breach,
CommitTx: spendTx, CommitTx: spendTx,
CommitTxBlockHeight: breachHeight,
SignDesc: *br.LocalOutputSignDesc, SignDesc: *br.LocalOutputSignDesc,
KeyRing: keyRing, KeyRing: keyRing,
CsvDelay: ourDelay, CsvDelay: ourDelay,
@@ -2295,6 +2298,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// At this point, we'll check to see if we need any extra // At this point, we'll check to see if we need any extra
// resolution data for this output. // resolution data for this output.
//
//nolint:ll
resolveReq := ResolutionReq{ resolveReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanState.ChanType, ChanType: chanState.ChanType,
@@ -2304,6 +2309,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
Type: input.TaprootCommitmentRevoke, Type: input.TaprootCommitmentRevoke,
CloseType: Breach, CloseType: Breach,
CommitTx: spendTx, CommitTx: spendTx,
CommitTxBlockHeight: breachHeight,
SignDesc: *br.RemoteOutputSignDesc, SignDesc: *br.RemoteOutputSignDesc,
KeyRing: keyRing, KeyRing: keyRing,
CsvDelay: theirDelay, CsvDelay: theirDelay,
@@ -6886,6 +6892,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen
// First, we'll generate the commitment point and the revocation point // First, we'll generate the commitment point and the revocation point
// so we can re-construct the HTLC state and also our payment key. // so we can re-construct the HTLC state and also our payment key.
commitType := lntypes.Remote commitType := lntypes.Remote
commitTxHeight := uint32(commitSpend.SpendingHeight)
keyRing := DeriveCommitmentKeys( keyRing := DeriveCommitmentKeys(
commitPoint, commitType, chanState.ChanType, commitPoint, commitType, chanState.ChanType,
&chanState.LocalChanCfg, &chanState.RemoteChanCfg, &chanState.LocalChanCfg, &chanState.RemoteChanCfg,
@@ -6920,8 +6927,9 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen
chainfee.SatPerKWeight(remoteCommit.FeePerKw), commitType, chainfee.SatPerKWeight(remoteCommit.FeePerKw), commitType,
signer, remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg, signer, remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, commitSpend.SpendingTx, &chanState.RemoteChanCfg, commitSpend.SpendingTx,
chanState.ChanType, isRemoteInitiator, leaseExpiry, chanState, commitTxHeight, chanState.ChanType,
auxResult.AuxLeaves, auxResolver, isRemoteInitiator, leaseExpiry, chanState, auxResult.AuxLeaves,
auxResolver,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to create htlc resolutions: %w", return nil, fmt.Errorf("unable to create htlc resolutions: %w",
@@ -7009,6 +7017,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen
// At this point, we'll check to see if we need any extra // At this point, we'll check to see if we need any extra
// resolution data for this output. // resolution data for this output.
//
//nolint:ll
resolveReq := ResolutionReq{ resolveReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanState.ChanType, ChanType: chanState.ChanType,
@@ -7019,6 +7029,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen
Type: input.TaprootRemoteCommitSpend, Type: input.TaprootRemoteCommitSpend,
CloseType: RemoteForceClose, CloseType: RemoteForceClose,
CommitTx: commitTxBroadcast, CommitTx: commitTxBroadcast,
CommitTxBlockHeight: commitTxHeight,
ContractPoint: *selfPoint, ContractPoint: *selfPoint,
SignDesc: commitResolution.SelfOutputSignDesc, SignDesc: commitResolution.SelfOutputSignDesc,
KeyRing: keyRing, KeyRing: keyRing,
@@ -7209,7 +7220,7 @@ type HtlcResolutions struct {
// the remote party's commitment transaction. // the remote party's commitment transaction.
func newOutgoingHtlcResolution(signer input.Signer, func newOutgoingHtlcResolution(signer input.Signer,
localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx, localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx,
htlc *channeldb.HTLC, keyRing *CommitmentKeyRing, commitTxHeight uint32, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32, feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32,
whoseCommit lntypes.ChannelParty, isCommitFromInitiator bool, whoseCommit lntypes.ChannelParty, isCommitFromInitiator bool,
chanType channeldb.ChannelType, chanState *channeldb.OpenChannel, chanType channeldb.ChannelType, chanState *channeldb.OpenChannel,
@@ -7285,6 +7296,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
} }
} }
//nolint:ll
resReq := ResolutionReq{ resReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanType, ChanType: chanType,
@@ -7295,6 +7307,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
Type: input.TaprootHtlcOfferedRemoteTimeout, Type: input.TaprootHtlcOfferedRemoteTimeout,
CloseType: RemoteForceClose, CloseType: RemoteForceClose,
CommitTx: commitTx, CommitTx: commitTx,
CommitTxBlockHeight: commitTxHeight,
ContractPoint: op, ContractPoint: op,
SignDesc: signDesc, SignDesc: signDesc,
KeyRing: keyRing, KeyRing: keyRing,
@@ -7513,16 +7526,18 @@ func newOutgoingHtlcResolution(signer input.Signer,
// the sweeping sub-system. // the sweeping sub-system.
resolveRes := fn.MapOptionZ( resolveRes := fn.MapOptionZ(
auxResolver, func(a AuxContractResolver) fn.Result[tlv.Blob] { auxResolver, func(a AuxContractResolver) fn.Result[tlv.Blob] {
//nolint:ll
resReq := ResolutionReq{ resReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanType, ChanType: chanType,
ShortChanID: chanState.ShortChanID(), ShortChanID: chanState.ShortChanID(),
Initiator: chanState.IsInitiator, Initiator: chanState.IsInitiator,
CommitBlob: chanState.LocalCommitment.CustomBlob, //nolint:ll CommitBlob: chanState.LocalCommitment.CustomBlob,
FundingBlob: chanState.CustomBlob, FundingBlob: chanState.CustomBlob,
Type: input.TaprootHtlcLocalOfferedTimeout, //nolint:ll Type: input.TaprootHtlcLocalOfferedTimeout,
CloseType: LocalForceClose, CloseType: LocalForceClose,
CommitTx: commitTx, CommitTx: commitTx,
CommitTxBlockHeight: commitTxHeight,
ContractPoint: op, ContractPoint: op,
SignDesc: sweepSignDesc, SignDesc: sweepSignDesc,
KeyRing: keyRing, KeyRing: keyRing,
@@ -7530,14 +7545,14 @@ func newOutgoingHtlcResolution(signer input.Signer,
HtlcAmt: btcutil.Amount(txOut.Value), HtlcAmt: btcutil.Amount(txOut.Value),
CommitCsvDelay: csvDelay, CommitCsvDelay: csvDelay,
CltvDelay: fn.Some(htlc.RefundTimeout), CltvDelay: fn.Some(htlc.RefundTimeout),
CommitFee: chanState.LocalCommitment.CommitFee, //nolint:ll CommitFee: chanState.LocalCommitment.CommitFee,
HtlcID: fn.Some(htlc.HtlcIndex), HtlcID: fn.Some(htlc.HtlcIndex),
PayHash: fn.Some(htlc.RHash), PayHash: fn.Some(htlc.RHash),
AuxSigDesc: fn.Some(AuxSigDesc{ AuxSigDesc: fn.Some(AuxSigDesc{
SignDetails: *txSignDetails, SignDetails: *txSignDetails,
AuxSig: func() []byte { AuxSig: func() []byte {
tlvType := htlcCustomSigType.TypeVal() //nolint:ll tlvType := htlcCustomSigType.TypeVal()
return htlc.CustomRecords[uint64(tlvType)] //nolint:ll return htlc.CustomRecords[uint64(tlvType)]
}(), }(),
}), }),
} }
@@ -7573,7 +7588,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
// TODO(roasbeef) consolidate code with above func // TODO(roasbeef) consolidate code with above func
func newIncomingHtlcResolution(signer input.Signer, func newIncomingHtlcResolution(signer input.Signer,
localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx, localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx,
htlc *channeldb.HTLC, keyRing *CommitmentKeyRing, commitTxHeight uint32, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32, feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32,
whoseCommit lntypes.ChannelParty, isCommitFromInitiator bool, whoseCommit lntypes.ChannelParty, isCommitFromInitiator bool,
chanType channeldb.ChannelType, chanState *channeldb.OpenChannel, chanType channeldb.ChannelType, chanState *channeldb.OpenChannel,
@@ -7648,6 +7663,7 @@ func newIncomingHtlcResolution(signer input.Signer,
} }
} }
//nolint:ll
resReq := ResolutionReq{ resReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanType, ChanType: chanType,
@@ -7658,6 +7674,7 @@ func newIncomingHtlcResolution(signer input.Signer,
FundingBlob: chanState.CustomBlob, FundingBlob: chanState.CustomBlob,
CloseType: RemoteForceClose, CloseType: RemoteForceClose,
CommitTx: commitTx, CommitTx: commitTx,
CommitTxBlockHeight: commitTxHeight,
ContractPoint: op, ContractPoint: op,
SignDesc: signDesc, SignDesc: signDesc,
KeyRing: keyRing, KeyRing: keyRing,
@@ -7867,28 +7884,30 @@ func newIncomingHtlcResolution(signer input.Signer,
resolveRes := fn.MapOptionZ( resolveRes := fn.MapOptionZ(
auxResolver, func(a AuxContractResolver) fn.Result[tlv.Blob] { auxResolver, func(a AuxContractResolver) fn.Result[tlv.Blob] {
//nolint:ll
resReq := ResolutionReq{ resReq := ResolutionReq{
ChanPoint: chanState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
ChanType: chanType, ChanType: chanType,
ShortChanID: chanState.ShortChanID(), ShortChanID: chanState.ShortChanID(),
Initiator: chanState.IsInitiator, Initiator: chanState.IsInitiator,
CommitBlob: chanState.LocalCommitment.CustomBlob, //nolint:ll CommitBlob: chanState.LocalCommitment.CustomBlob,
Type: input.TaprootHtlcAcceptedLocalSuccess, //nolint:ll Type: input.TaprootHtlcAcceptedLocalSuccess,
FundingBlob: chanState.CustomBlob, FundingBlob: chanState.CustomBlob,
CloseType: LocalForceClose, CloseType: LocalForceClose,
CommitTx: commitTx, CommitTx: commitTx,
CommitTxBlockHeight: commitTxHeight,
ContractPoint: op, ContractPoint: op,
SignDesc: sweepSignDesc, SignDesc: sweepSignDesc,
KeyRing: keyRing, KeyRing: keyRing,
HtlcID: fn.Some(htlc.HtlcIndex), HtlcID: fn.Some(htlc.HtlcIndex),
CsvDelay: htlcCsvDelay, CsvDelay: htlcCsvDelay,
CommitFee: chanState.LocalCommitment.CommitFee, //nolint:ll CommitFee: chanState.LocalCommitment.CommitFee,
PayHash: fn.Some(htlc.RHash), PayHash: fn.Some(htlc.RHash),
AuxSigDesc: fn.Some(AuxSigDesc{ AuxSigDesc: fn.Some(AuxSigDesc{
SignDetails: *txSignDetails, SignDetails: *txSignDetails,
AuxSig: func() []byte { AuxSig: func() []byte {
tlvType := htlcCustomSigType.TypeVal() //nolint:ll tlvType := htlcCustomSigType.TypeVal()
return htlc.CustomRecords[uint64(tlvType)] //nolint:ll return htlc.CustomRecords[uint64(tlvType)]
}(), }(),
}), }),
CommitCsvDelay: csvDelay, CommitCsvDelay: csvDelay,
@@ -7949,9 +7968,10 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight,
whoseCommit lntypes.ChannelParty, signer input.Signer, whoseCommit lntypes.ChannelParty, signer input.Signer,
htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig, localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
commitTx *wire.MsgTx, chanType channeldb.ChannelType, commitTx *wire.MsgTx, commitTxHeight uint32,
isCommitFromInitiator bool, leaseExpiry uint32, chanType channeldb.ChannelType, isCommitFromInitiator bool,
chanState *channeldb.OpenChannel, auxLeaves fn.Option[CommitAuxLeaves], leaseExpiry uint32, chanState *channeldb.OpenChannel,
auxLeaves fn.Option[CommitAuxLeaves],
auxResolver fn.Option[AuxContractResolver]) (*HtlcResolutions, error) { auxResolver fn.Option[AuxContractResolver]) (*HtlcResolutions, error) {
// TODO(roasbeef): don't need to swap csv delay? // TODO(roasbeef): don't need to swap csv delay?
@@ -7984,8 +8004,8 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight,
// Otherwise, we'll create an incoming HTLC resolution // Otherwise, we'll create an incoming HTLC resolution
// as we can satisfy the contract. // as we can satisfy the contract.
ihr, err := newIncomingHtlcResolution( ihr, err := newIncomingHtlcResolution(
signer, localChanCfg, commitTx, &htlc, signer, localChanCfg, commitTx, commitTxHeight,
keyRing, feePerKw, uint32(csvDelay), &htlc, keyRing, feePerKw, uint32(csvDelay),
leaseExpiry, whoseCommit, isCommitFromInitiator, leaseExpiry, whoseCommit, isCommitFromInitiator,
chanType, chanState, auxLeaves, auxResolver, chanType, chanState, auxLeaves, auxResolver,
) )
@@ -7999,10 +8019,10 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight,
} }
ohr, err := newOutgoingHtlcResolution( ohr, err := newOutgoingHtlcResolution(
signer, localChanCfg, commitTx, &htlc, keyRing, signer, localChanCfg, commitTx, commitTxHeight, &htlc,
feePerKw, uint32(csvDelay), leaseExpiry, whoseCommit, keyRing, feePerKw, uint32(csvDelay), leaseExpiry,
isCommitFromInitiator, chanType, chanState, auxLeaves, whoseCommit, isCommitFromInitiator, chanType, chanState,
auxResolver, auxLeaves, auxResolver,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("outgoing resolution "+ return nil, fmt.Errorf("outgoing resolution "+
@@ -8148,7 +8168,8 @@ func (lc *LightningChannel) ForceClose(opts ...ForceCloseOpt) (
localCommitment := lc.channelState.LocalCommitment localCommitment := lc.channelState.LocalCommitment
summary, err := NewLocalForceCloseSummary( summary, err := NewLocalForceCloseSummary(
lc.channelState, lc.Signer, commitTx, lc.channelState, lc.Signer, commitTx,
localCommitment.CommitHeight, lc.leafStore, lc.auxResolver, 0, localCommitment.CommitHeight, lc.leafStore,
lc.auxResolver,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to gen force close "+ return nil, fmt.Errorf("unable to gen force close "+
@@ -8165,8 +8186,8 @@ func (lc *LightningChannel) ForceClose(opts ...ForceCloseOpt) (
// channel state. The passed commitTx must be a fully signed commitment // channel state. The passed commitTx must be a fully signed commitment
// transaction corresponding to localCommit. // transaction corresponding to localCommit.
func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
signer input.Signer, commitTx *wire.MsgTx, stateNum uint64, signer input.Signer, commitTx *wire.MsgTx, commitTxHeight uint32,
leafStore fn.Option[AuxLeafStore], stateNum uint64, leafStore fn.Option[AuxLeafStore],
auxResolver fn.Option[AuxContractResolver]) (*LocalForceCloseSummary, auxResolver fn.Option[AuxContractResolver]) (*LocalForceCloseSummary,
error) { error) {
@@ -8301,7 +8322,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
func(a AuxContractResolver) fn.Result[tlv.Blob] { func(a AuxContractResolver) fn.Result[tlv.Blob] {
//nolint:ll //nolint:ll
return a.ResolveContract(ResolutionReq{ return a.ResolveContract(ResolutionReq{
ChanPoint: chanState.FundingOutpoint, //nolint:ll ChanPoint: chanState.FundingOutpoint,
ChanType: chanState.ChanType, ChanType: chanState.ChanType,
ShortChanID: chanState.ShortChanID(), ShortChanID: chanState.ShortChanID(),
Initiator: chanState.IsInitiator, Initiator: chanState.IsInitiator,
@@ -8310,6 +8331,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
Type: input.TaprootLocalCommitSpend, Type: input.TaprootLocalCommitSpend,
CloseType: LocalForceClose, CloseType: LocalForceClose,
CommitTx: commitTx, CommitTx: commitTx,
CommitTxBlockHeight: commitTxHeight,
ContractPoint: commitResolution.SelfOutPoint, ContractPoint: commitResolution.SelfOutPoint,
SignDesc: commitResolution.SelfOutputSignDesc, SignDesc: commitResolution.SelfOutputSignDesc,
KeyRing: keyRing, KeyRing: keyRing,
@@ -8334,9 +8356,9 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel,
htlcResolutions, err := extractHtlcResolutions( htlcResolutions, err := extractHtlcResolutions(
chainfee.SatPerKWeight(localCommit.FeePerKw), lntypes.Local, chainfee.SatPerKWeight(localCommit.FeePerKw), lntypes.Local,
signer, localCommit.Htlcs, keyRing, &chanState.LocalChanCfg, signer, localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, commitTx, chanState.ChanType, &chanState.RemoteChanCfg, commitTx, commitTxHeight,
chanState.IsInitiator, leaseExpiry, chanState, chanState.ChanType, chanState.IsInitiator, leaseExpiry,
auxResult.AuxLeaves, auxResolver, chanState, auxResult.AuxLeaves, auxResolver,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to gen htlc resolution: %w", err) return nil, fmt.Errorf("unable to gen htlc resolution: %w", err)