diff --git a/lnwallet/aux_resolutions.go b/lnwallet/aux_resolutions.go index 14802c57c7..35d0bb37d1 100644 --- a/lnwallet/aux_resolutions.go +++ b/lnwallet/aux_resolutions.go @@ -94,6 +94,13 @@ type ResolutionReq struct { // KeyRing is the key ring for the channel. KeyRing *CommitmentKeyRing + // CommitHeight is the commitment height of the commitment being + // resolved, when known. Downstream resolvers can use this to detect a + // height-0 commitment (i.e. an immediate post-funding force close, + // before the channel_ready commit point rotation), where KeyRing is + // derived from the initial commitment point. + CommitHeight fn.Option[uint64] + // CsvDelay is the CSV delay for the local output for this commitment. CsvDelay uint32 diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 78ca895655..f87615582b 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -2282,6 +2282,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, CommitTxBlockHeight: breachHeight, SignDesc: *br.LocalOutputSignDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), CsvDelay: ourDelay, BreachCsvDelay: fn.Some(theirDelay), CommitFee: chanState.RemoteCommitment.CommitFee, @@ -2365,6 +2366,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, CommitTxBlockHeight: breachHeight, SignDesc: *br.RemoteOutputSignDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), CsvDelay: theirDelay, BreachCsvDelay: fn.Some(theirDelay), CommitFee: chanState.RemoteCommitment.CommitFee, @@ -7119,7 +7121,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen chainfee.SatPerKWeight(remoteCommit.FeePerKw), commitType, signer, remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, commitSpend.SpendingTx, - commitTxHeight, chanState.ChanType, + commitTxHeight, remoteCommit.CommitHeight, chanState.ChanType, isRemoteInitiator, leaseExpiry, chanState, auxResult.AuxLeaves, auxResolver, ) @@ -7225,6 +7227,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, //nolint:funlen ContractPoint: *selfPoint, SignDesc: commitResolution.SelfOutputSignDesc, KeyRing: keyRing, + CommitHeight: fn.Some(remoteCommit.CommitHeight), CsvDelay: maturityDelay, CommitFee: chanState.RemoteCommitment.CommitFee, } @@ -7412,7 +7415,8 @@ type HtlcResolutions struct { // the remote party's commitment transaction. func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx, - commitTxHeight uint32, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing, + commitTxHeight uint32, stateNum uint64, htlc *channeldb.HTLC, + keyRing *CommitmentKeyRing, feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32, whoseCommit lntypes.ChannelParty, isCommitFromInitiator bool, chanType channeldb.ChannelType, chanState *channeldb.OpenChannel, @@ -7503,6 +7507,7 @@ func newOutgoingHtlcResolution(signer input.Signer, ContractPoint: op, SignDesc: signDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), CsvDelay: htlcCsvDelay, CltvDelay: fn.Some(htlc.RefundTimeout), CommitFee: chanState.RemoteCommitment.CommitFee, @@ -7739,6 +7744,7 @@ func newOutgoingHtlcResolution(signer input.Signer, ContractPoint: op, SignDesc: sweepSignDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), CsvDelay: htlcCsvDelay, HtlcAmt: btcutil.Amount(txOut.Value), CommitCsvDelay: csvDelay, @@ -7786,7 +7792,8 @@ func newOutgoingHtlcResolution(signer input.Signer, // TODO(roasbeef) consolidate code with above func func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig, commitTx *wire.MsgTx, - commitTxHeight uint32, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing, + commitTxHeight uint32, stateNum uint64, htlc *channeldb.HTLC, + keyRing *CommitmentKeyRing, feePerKw chainfee.SatPerKWeight, csvDelay, leaseExpiry uint32, whoseCommit lntypes.ChannelParty, isCommitFromInitiator bool, chanType channeldb.ChannelType, chanState *channeldb.OpenChannel, @@ -7876,6 +7883,7 @@ func newIncomingHtlcResolution(signer input.Signer, ContractPoint: op, SignDesc: signDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), HtlcID: fn.Some(htlc.HtlcIndex), CsvDelay: htlcCsvDelay, CltvDelay: fn.Some(htlc.RefundTimeout), @@ -8103,6 +8111,7 @@ func newIncomingHtlcResolution(signer input.Signer, ContractPoint: op, SignDesc: sweepSignDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), HtlcID: fn.Some(htlc.HtlcIndex), CsvDelay: htlcCsvDelay, CommitFee: chanState.LocalCommitment.CommitFee, @@ -8172,7 +8181,7 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, whoseCommit lntypes.ChannelParty, signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing, localChanCfg, remoteChanCfg *channeldb.ChannelConfig, - commitTx *wire.MsgTx, commitTxHeight uint32, + commitTx *wire.MsgTx, commitTxHeight uint32, stateNum uint64, chanType channeldb.ChannelType, isCommitFromInitiator bool, leaseExpiry uint32, chanState *channeldb.OpenChannel, auxLeaves fn.Option[CommitAuxLeaves], @@ -8209,9 +8218,10 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, // as we can satisfy the contract. ihr, err := newIncomingHtlcResolution( signer, localChanCfg, commitTx, commitTxHeight, - &htlc, keyRing, feePerKw, uint32(csvDelay), - leaseExpiry, whoseCommit, isCommitFromInitiator, - chanType, chanState, auxLeaves, auxResolver, + stateNum, &htlc, keyRing, feePerKw, + uint32(csvDelay), leaseExpiry, whoseCommit, + isCommitFromInitiator, chanType, chanState, + auxLeaves, auxResolver, ) if err != nil { return nil, fmt.Errorf("incoming resolution "+ @@ -8223,10 +8233,10 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, } ohr, err := newOutgoingHtlcResolution( - signer, localChanCfg, commitTx, commitTxHeight, &htlc, - keyRing, feePerKw, uint32(csvDelay), leaseExpiry, - whoseCommit, isCommitFromInitiator, chanType, chanState, - auxLeaves, auxResolver, + signer, localChanCfg, commitTx, commitTxHeight, + stateNum, &htlc, keyRing, feePerKw, uint32(csvDelay), + leaseExpiry, whoseCommit, isCommitFromInitiator, + chanType, chanState, auxLeaves, auxResolver, ) if err != nil { return nil, fmt.Errorf("outgoing resolution "+ @@ -8539,6 +8549,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, ContractPoint: commitResolution.SelfOutPoint, SignDesc: commitResolution.SelfOutputSignDesc, KeyRing: keyRing, + CommitHeight: fn.Some(stateNum), CsvDelay: csvTimeout, CommitFee: chanState.LocalCommitment.CommitFee, }) @@ -8560,7 +8571,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, htlcResolutions, err := extractHtlcResolutions( chainfee.SatPerKWeight(localCommit.FeePerKw), lntypes.Local, signer, localCommit.Htlcs, keyRing, &chanState.LocalChanCfg, - &chanState.RemoteChanCfg, commitTx, commitTxHeight, + &chanState.RemoteChanCfg, commitTx, commitTxHeight, stateNum, chanState.ChanType, chanState.IsInitiator, leaseExpiry, chanState, auxResult.AuxLeaves, auxResolver, )