From ecf6d758a2a293ef82546cf8e9fea2a5b402e588 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Tue, 16 Jan 2018 18:17:18 -0800 Subject: [PATCH] lnwallet: add distinct CommitOutputResolution for resolving commit outputs on-chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, we modify both the ForceCloseSummary, and the UnilateralClosureSummary to return the items needed to sweep the commitment output distinctly. By doing this, it’s now possible to pass a dedicated struct to a sub-system in order to allow it to sweep a commitment output. As the maturity delay is a part of this new struct, this tells the caller if this was on the local commitment (CSV required) or on the remote commitment (no CSV required). --- lnwallet/channel.go | 156 ++++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 36002a34..3bba1892 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -2065,6 +2065,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven // // TODO(roasbeef): include HTLC's // * and time-locked balance, NEED TO??? + localBalance := lc.channelState.LocalCommitment.LocalBalance.ToSatoshis() closeSummary := channeldb.ChannelCloseSummary{ ChanPoint: lc.channelState.FundingOutpoint, ChainHash: lc.channelState.ChainHash, @@ -2072,7 +2073,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven CloseHeight: spendHeight, RemotePub: lc.channelState.IdentityPub, Capacity: lc.Capacity, - SettledBalance: lc.channelState.LocalCommitment.LocalBalance.ToSatoshis(), + SettledBalance: localBalance, CloseType: channeldb.ForceClose, IsPending: true, } @@ -2127,31 +2128,32 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven // With the HTLC's taken care of, we'll generate the sign // descriptor necessary to sweep our commitment output, but // only if we had a non-trimmed balance. - var selfSignDesc *SignDescriptor + var commitResolution *CommitOutputResolution if selfPoint != nil { localPayBase := lc.localChanCfg.PaymentBasePoint localBalance := lc.channelState.LocalCommitment.LocalBalance.ToSatoshis() - selfSignDesc = &SignDescriptor{ - PubKey: localPayBase, - SingleTweak: keyRing.localCommitKeyTweak, - WitnessScript: selfP2WKH, - Output: &wire.TxOut{ - Value: int64(localBalance), - PkScript: selfP2WKH, + commitResolution = &CommitOutputResolution{ + SelfOutPoint: *selfPoint, + SelfOutputSignDesc: SignDescriptor{ + PubKey: localPayBase, + SingleTweak: keyRing.localCommitKeyTweak, + WitnessScript: selfP2WKH, + Output: &wire.TxOut{ + Value: int64(localBalance), + PkScript: selfP2WKH, + }, + HashType: txscript.SigHashAll, }, - HashType: txscript.SigHashAll, + MaturityDelay: 0, } } - // We'll also send all the details necessary to re-claim funds - // that are suspended within any contracts. - unilateralCloseSummary := &UnilateralCloseSummary{ + uniCloseSummary := &UnilateralCloseSummary{ SpendDetail: commitSpend, ChannelCloseSummary: closeSummary, - SelfOutPoint: selfPoint, - SelfOutputSignDesc: selfSignDesc, - MaturityDelay: uint32(lc.remoteChanCfg.CsvDelay), + CommitResolution: commitResolution, HtlcResolutions: htlcResolutions, + ChanSnapshot: *lc.channelState.Snapshot(), } // TODO(roasbeef): send msg before writing to disk @@ -2163,8 +2165,10 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven // commitment transaction broadcast. close(lc.UnilateralCloseSignal) + // We'll also send all the details necessary to re-claim funds + // that are suspended within any contracts. select { - case lc.UnilateralClose <- unilateralCloseSummary: + case lc.UnilateralClose <- uniCloseSummary: case <-lc.observerQuit: walletLog.Errorf("channel shutting down") return @@ -2240,6 +2244,7 @@ func (lc *LightningChannel) closeObserver(channelCloseNtfn *chainntnfs.SpendEven SettledBalance: settledBalance, CloseType: channeldb.BreachClose, IsPending: true, + ShortChanID: lc.channelState.ShortChanID, } err = lc.DeleteState(&closeSummary) @@ -4366,6 +4371,25 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) { return commitTx, nil } +// CommitOutputResolution carries the necessary information required to allow +// us to sweep our direct commitment output in the case that either party goes +// to chain. +type CommitOutputResolution struct { + // SelfOutPoint is the full outpoint that points to out pay-to-self + // output within the closing commitment transaction. + SelfOutPoint wire.OutPoint + + // SelfOutputSignDesc is a fully populated sign descriptor capable of + // generating a valid signature to sweep the output paying to us. + SelfOutputSignDesc SignDescriptor + + // MaturityDelay is the relative time-lock, in blocks for all outputs + // that pay to the local party within the broadcast commitment + // transaction. This value will be non-zero iff, this output was on our + // commitment transaction. + MaturityDelay uint32 +} + // UnilateralCloseSummary describes the details of a detected unilateral // channel closure. This includes the information about with which // transactions, and block the channel was unilaterally closed, as well as @@ -4384,19 +4408,21 @@ type UnilateralCloseSummary struct { // channel and in which state is was closed. channeldb.ChannelCloseSummary - // SelfOutPoint is the full outpoint that points to our non-delayed - // pay-to-self output within the commitment transaction of the remote - // party. - SelfOutPoint *wire.OutPoint + // CommitResolution contains all the data required to sweep the output + // to ourselves. If this is our commitment transaction, then we'll need + // to wait a time delay before we can sweep the output. + // + // NOTE: If our commitment delivery output is below the dust limit, + // then this will be nil. + CommitResolution *CommitOutputResolution + + + // ChanSnapshot is a snapshot of the final state of the channel at the + // time it was closed. + ChanSnapshot channeldb.ChannelSnapshot +} - // SelfOutputSignDesc is a fully populated sign descriptor capable of - // generating a valid signature to sweep the output paying to us - SelfOutputSignDesc *SignDescriptor - // MaturityDelay is the relative time-lock, in blocks for all outputs - // that pay to the local party within the broadcast commitment - // transaction. - MaturityDelay uint32 // HtlcResolutions is a slice of HTLC resolutions which allows the // local node to sweep any outgoing HTLC"s after the timeout period has @@ -4577,31 +4603,28 @@ type ForceCloseSummary struct { // force closed. ChanPoint wire.OutPoint - // SelfOutpoint is the output created by the above close tx which is - // spendable by us after a relative time delay. - SelfOutpoint wire.OutPoint - // CloseTx is the transaction which closed the channel on-chain. If we // initiate the force close, then this'll be our latest commitment // state. Otherwise, this'll be the state that the remote peer // broadcasted on-chain. CloseTx *wire.MsgTx - // SelfOutputSignDesc is a fully populated sign descriptor capable of - // generating a valid signature to sweep the self output. + // CommitResolution contains all the data required to sweep the output + // to ourselves. If this is our commitment transaction, then we'll need + // to wait a time delay before we can sweep the output. // - // NOTE: If the commitment delivery output of the force closing party - // is below the dust limit, then this will be nil. - SelfOutputSignDesc *SignDescriptor + // NOTE: If our commitment delivery output is below the dust limit, + // then this will be nil. + CommitResolution *CommitOutputResolution - // SelfOutputMaturity is the relative maturity period before the above - // output can be claimed. - SelfOutputMaturity uint32 + // HtlcResolutions contains all the data required to sweep any outgoing + // HTLC's and incoming HTLc's we now the preimage to. For each of these + // HTLC's, we'll need to go to the second level to sweep them fully. + HtlcResolutions *HtlcResolutions - // HtlcResolutions is a slice of HTLC resolutions which allows the - // local node to sweep any outgoing HTLC"s after the timeout period has - // passed. - HtlcResolutions []OutgoingHtlcResolution + // ChanSnapshot is a snapshot of the final state of the channel at the + // time it was closed. + ChanSnapshot channeldb.ChannelSnapshot } // ForceClose executes a unilateral closure of the transaction at the current @@ -4655,9 +4678,8 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) { // We'll return the details of this output to the caller so they can // sweep it once it's mature. var ( - delayIndex uint32 - delayScript []byte - selfSignDesc *SignDescriptor + delayIndex uint32 + delayScript []byte ) for i, txOut := range commitTx.TxOut { if !bytes.Equal(payToUsScriptHash, txOut.PkScript) { @@ -4677,19 +4699,27 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) { // set as the caller will decide these values once sweeping the output. // If the output is non-existent (dust), have the sign descriptor be // nil. + var commitResolution *CommitOutputResolution if len(delayScript) != 0 { singleTweak := SingleTweakBytes(commitPoint, lc.localChanCfg.DelayBasePoint) localBalance := localCommitment.LocalBalance - selfSignDesc = &SignDescriptor{ - PubKey: lc.localChanCfg.DelayBasePoint, - SingleTweak: singleTweak, - WitnessScript: selfScript, - Output: &wire.TxOut{ - PkScript: delayScript, - Value: int64(localBalance.ToSatoshis()), + commitResolution = &CommitOutputResolution{ + SelfOutPoint: wire.OutPoint{ + Hash: commitTx.TxHash(), + Index: delayIndex, }, - HashType: txscript.SigHashAll, + SelfOutputSignDesc: SignDescriptor{ + PubKey: lc.localChanCfg.DelayBasePoint, + SingleTweak: singleTweak, + WitnessScript: selfScript, + Output: &wire.TxOut{ + PkScript: delayScript, + Value: int64(localBalance.ToSatoshis()), + }, + HashType: txscript.SigHashAll, + }, + MaturityDelay: csvTimeout, } } @@ -4711,15 +4741,11 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) { close(lc.ForceCloseSignal) return &ForceCloseSummary{ - ChanPoint: lc.channelState.FundingOutpoint, - SelfOutpoint: wire.OutPoint{ - Hash: commitTx.TxHash(), - Index: delayIndex, - }, - CloseTx: commitTx, - SelfOutputSignDesc: selfSignDesc, - SelfOutputMaturity: csvTimeout, - HtlcResolutions: htlcResolutions, + ChanPoint: lc.channelState.FundingOutpoint, + CloseTx: commitTx, + CommitResolution: commitResolution, + HtlcResolutions: htlcResolutions, + ChanSnapshot: *lc.channelState.Snapshot(), }, nil } @@ -5300,7 +5326,7 @@ func (lc *LightningChannel) ActiveHtlcs() []channeldb.HTLC { remoteHtlcs[onionHash] = struct{}{} } - // Now tht we know which HTLC's they have, we'll only mark the HTLC's + // Now that we know which HTLC's they have, we'll only mark the HTLC's // as active if *we* know them as well. activeHtlcs := make([]channeldb.HTLC, 0, len(remoteHtlcs)) for _, htlc := range lc.channelState.LocalCommitment.Htlcs {