lnwallet/channel: add NewLocalForceCloseSummary

This commit renames ForceCloseSummary to LocalForceCloseSummary, and
adds a new method NewLocalForceCloseSummary that can be used to derive a
LocalForceCloseSummary if our commitment transaction gets confirmed
in-chain. It is meant to accompany the NewUnilateralCloseSummary method,
which is used for the same purpose in the event of a remote commitment
being seen in-chain.
This commit is contained in:
Johan T. Halseth 2018-03-19 15:19:19 +01:00
parent b7875fce4c
commit 8e77e1e6eb
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
3 changed files with 55 additions and 39 deletions

@ -196,7 +196,7 @@ func newActiveChannelArbitrator(channel *channeldb.OpenChannel,
ChanPoint: chanPoint, ChanPoint: chanPoint,
ShortChanID: channel.ShortChanID, ShortChanID: channel.ShortChanID,
BlockEpochs: blockEpoch, BlockEpochs: blockEpoch,
ForceCloseChan: func() (*lnwallet.ForceCloseSummary, error) { ForceCloseChan: func() (*lnwallet.LocalForceCloseSummary, error) {
// With the channels fetched, attempt to locate // With the channels fetched, attempt to locate
// the target channel according to its channel // the target channel according to its channel
// point. // point.

@ -89,7 +89,7 @@ type ChannelArbitratorConfig struct {
// is watching over. We'll use this when we decide that we need to go // is watching over. We'll use this when we decide that we need to go
// to chain. The returned summary contains all items needed to // to chain. The returned summary contains all items needed to
// eventually resolve all outputs on chain. // eventually resolve all outputs on chain.
ForceCloseChan func() (*lnwallet.ForceCloseSummary, error) ForceCloseChan func() (*lnwallet.LocalForceCloseSummary, error)
// CloseChannel is a function closure that marks a channel under watch // CloseChannel is a function closure that marks a channel under watch
// as "closing". In this phase, we will no longer accept any updates to // as "closing". In this phase, we will no longer accept any updates to

@ -5203,23 +5203,24 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
}, nil }, nil
} }
// ForceCloseSummary describes the final commitment state before the channel is // LocalForceCloseSummary describes the final commitment state before the
// locked-down to initiate a force closure by broadcasting the latest state // channel is locked-down to initiate a force closure by broadcasting the
// on-chain. The summary includes all the information required to claim all // latest state on-chain. If we intend to broadcast this this state, the
// rightfully owned outputs. // channel should not be used after generating this close summary. The summary
type ForceCloseSummary struct { // includes all the information required to claim all rightfully owned outputs
// when the commitment gets confirmed.
type LocalForceCloseSummary struct {
// ChanPoint is the outpoint that created the channel which has been // ChanPoint is the outpoint that created the channel which has been
// force closed. // force closed.
ChanPoint wire.OutPoint ChanPoint wire.OutPoint
// CloseTx is the transaction which closed the channel on-chain. If we // CloseTx is the transaction which can be used to close the channel
// initiate the force close, then this will be our latest commitment // on-chain. When we initiate a force close, this will be our latest
// state. Otherwise, this will be the state that the remote peer // commitment state.
// broadcasted on-chain.
CloseTx *wire.MsgTx CloseTx *wire.MsgTx
// CommitResolution contains all the data required to sweep the output // CommitResolution contains all the data required to sweep the output
// to ourselves. If this is our commitment transaction, then we'll need // to ourselves. Since this is our commitment transaction, we'll need
// to wait a time delay before we can sweep the output. // to wait a time delay before we can sweep the output.
// //
// NOTE: If our commitment delivery output is below the dust limit, // NOTE: If our commitment delivery output is below the dust limit,
@ -5227,52 +5228,69 @@ type ForceCloseSummary struct {
CommitResolution *CommitOutputResolution CommitResolution *CommitOutputResolution
// HtlcResolutions contains all the data required to sweep any outgoing // 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 and incoming HTLc's we know the preimage to. For each of these
// HTLC's, we'll need to go to the second level to sweep them fully. // HTLC's, we'll need to go to the second level to sweep them fully.
HtlcResolutions *HtlcResolutions HtlcResolutions *HtlcResolutions
// ChanSnapshot is a snapshot of the final state of the channel at the // ChanSnapshot is a snapshot of the final state of the channel at the
// time it was closed. // time the summary was created.
ChanSnapshot channeldb.ChannelSnapshot ChanSnapshot channeldb.ChannelSnapshot
} }
// ForceClose executes a unilateral closure of the transaction at the current // ForceClose executes a unilateral closure of the transaction at the current
// lowest commitment height of the channel. Following a force closure, all // lowest commitment height of the channel. Following a force closure, all
// state transitions, or modifications to the state update logs will be // state transitions, or modifications to the state update logs will be
// rejected. Additionally, this function also returns a ForceCloseSummary which // rejected. Additionally, this function also returns a LocalForceCloseSummary
// includes the necessary details required to sweep all the time-locked within // which includes the necessary details required to sweep all the time-locked
// the commitment transaction. // outputs within the commitment transaction.
// //
// TODO(roasbeef): all methods need to abort if in dispute state // TODO(roasbeef): all methods need to abort if in dispute state
// TODO(roasbeef): method to generate CloseSummaries for when the remote peer // TODO(roasbeef): method to generate CloseSummaries for when the remote peer
// does a unilateral close // does a unilateral close
func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) { func (lc *LightningChannel) ForceClose() (*LocalForceCloseSummary, error) {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
// Set the channel state to indicate that the channel is now in a
// contested state.
lc.status = channelDispute
commitTx, err := lc.getSignedCommitTx() commitTx, err := lc.getSignedCommitTx()
if err != nil { if err != nil {
return nil, err return nil, err
} }
localCommitment := lc.channelState.LocalCommitment
summary, err := NewLocalForceCloseSummary(lc.channelState,
lc.signer, lc.pCache, commitTx, localCommitment)
if err != nil {
return nil, err
}
// Set the channel state to indicate that the channel is now in a
// contested state.
lc.status = channelDispute
return summary, nil
}
// NewLocalForceCloseSummary generates a LocalForceCloseSummary from the given
// channel state. The passed commitTx must be a fully signed commitment
// transaction corresponding to localCommit.
func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
pCache PreimageCache, commitTx *wire.MsgTx,
localCommit channeldb.ChannelCommitment) (*LocalForceCloseSummary, error) {
// Re-derive the original pkScript for to-self output within the // Re-derive the original pkScript for to-self output within the
// commitment transaction. We'll need this to find the corresponding // commitment transaction. We'll need this to find the corresponding
// output in the commitment transaction and potentially for creating // output in the commitment transaction and potentially for creating
// the sign descriptor. // the sign descriptor.
csvTimeout := uint32(lc.localChanCfg.CsvDelay) csvTimeout := uint32(chanState.LocalChanCfg.CsvDelay)
unusedRevocation, err := lc.channelState.RevocationProducer.AtIndex( revocation, err := chanState.RevocationProducer.AtIndex(
lc.currentHeight, localCommit.CommitHeight,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
commitPoint := ComputeCommitmentPoint(unusedRevocation[:]) commitPoint := ComputeCommitmentPoint(revocation[:])
keyRing := deriveCommitmentKeys(commitPoint, true, lc.localChanCfg, keyRing := deriveCommitmentKeys(commitPoint, true, &chanState.LocalChanCfg,
lc.remoteChanCfg) &chanState.RemoteChanCfg)
selfScript, err := commitScriptToSelf(csvTimeout, keyRing.DelayKey, selfScript, err := commitScriptToSelf(csvTimeout, keyRing.DelayKey,
keyRing.RevocationKey) keyRing.RevocationKey)
if err != nil { if err != nil {
@ -5300,8 +5318,6 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) {
break break
} }
localCommitment := lc.channelState.LocalCommitment
// With the necessary information gathered above, create a new sign // With the necessary information gathered above, create a new sign
// descriptor which is capable of generating the signature the caller // descriptor which is capable of generating the signature the caller
// needs to sweep this output. The hash cache, and input index are not // needs to sweep this output. The hash cache, and input index are not
@ -5311,16 +5327,16 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) {
var commitResolution *CommitOutputResolution var commitResolution *CommitOutputResolution
if len(delayScript) != 0 { if len(delayScript) != 0 {
singleTweak := SingleTweakBytes( singleTweak := SingleTweakBytes(
commitPoint, lc.localChanCfg.DelayBasePoint.PubKey, commitPoint, chanState.LocalChanCfg.DelayBasePoint.PubKey,
) )
localBalance := localCommitment.LocalBalance localBalance := localCommit.LocalBalance
commitResolution = &CommitOutputResolution{ commitResolution = &CommitOutputResolution{
SelfOutPoint: wire.OutPoint{ SelfOutPoint: wire.OutPoint{
Hash: commitTx.TxHash(), Hash: commitTx.TxHash(),
Index: delayIndex, Index: delayIndex,
}, },
SelfOutputSignDesc: SignDescriptor{ SelfOutputSignDesc: SignDescriptor{
KeyDesc: lc.localChanCfg.DelayBasePoint, KeyDesc: chanState.LocalChanCfg.DelayBasePoint,
SingleTweak: singleTweak, SingleTweak: singleTweak,
WitnessScript: selfScript, WitnessScript: selfScript,
Output: &wire.TxOut{ Output: &wire.TxOut{
@ -5338,19 +5354,19 @@ func (lc *LightningChannel) ForceClose() (*ForceCloseSummary, error) {
// outgoing HTLC's that we'll need to claim as well. // outgoing HTLC's that we'll need to claim as well.
txHash := commitTx.TxHash() txHash := commitTx.TxHash()
htlcResolutions, err := extractHtlcResolutions( htlcResolutions, err := extractHtlcResolutions(
SatPerKWeight(localCommitment.FeePerKw), true, lc.signer, SatPerKWeight(localCommit.FeePerKw), true, signer,
localCommitment.Htlcs, keyRing, lc.localChanCfg, localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
lc.remoteChanCfg, txHash, lc.pCache) &chanState.RemoteChanCfg, txHash, pCache)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ForceCloseSummary{ return &LocalForceCloseSummary{
ChanPoint: lc.channelState.FundingOutpoint, ChanPoint: chanState.FundingOutpoint,
CloseTx: commitTx, CloseTx: commitTx,
CommitResolution: commitResolution, CommitResolution: commitResolution,
HtlcResolutions: htlcResolutions, HtlcResolutions: htlcResolutions,
ChanSnapshot: *lc.channelState.Snapshot(), ChanSnapshot: *chanState.Snapshot(),
}, nil }, nil
} }