lnwallet: add new NewUnilateralCloseSummary function

In this commit, we add a new function that allows a caller to create a
UnilateralCloseSummary with the proper materials. This will be used
within a new sub-system to be added in a later commit to properly
dispatch notifications when on-chain events happen for a channel.
This commit is contained in:
Olaoluwa Osuntokun 2018-01-18 13:49:35 -08:00
parent 341c1678fc
commit 5bbe126c34
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 101 additions and 15 deletions

@ -4048,6 +4048,100 @@ type UnilateralCloseSummary struct {
// and also any incoming HTLC's that we know the pre-image to.
HtlcResolutions *HtlcResolutions
// RemoteCommit is the exact commitment state that the remote party
// broadcast.
RemoteCommit channeldb.ChannelCommitment
}
// NewUnilateralCloseSummary creates a new summary that provides the caller
// with all the information required to claim all funds on chain in the event
// that the remote party broadcasts their commitment.
func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
pCache PreimageCache, commitSpend *chainntnfs.SpendDetail,
remoteCommit channeldb.ChannelCommitment) (*UnilateralCloseSummary, error) {
// First, we'll generate the commitment point and the revocation point
// so we can re-construct the HTLC state and also our payment key.
commitPoint := chanState.RemoteCurrentRevocation
keyRing := deriveCommitmentKeys(
commitPoint, false, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg,
)
// Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we
// had on their commitment transaction.
htlcResolutions, err := extractHtlcResolutions(
remoteCommit.FeePerKw, false, signer, remoteCommit.Htlcs,
keyRing, &chanState.LocalChanCfg, &chanState.RemoteChanCfg,
*commitSpend.SpenderTxHash, pCache,
)
if err != nil {
return nil, fmt.Errorf("unable to create htlc resolutions: %v", err)
}
commitTxBroadcast := commitSpend.SpendingTx
// Before we can generate the proper sign descriptor, we'll need to
// locate the output index of our non-delayed output on the commitment
// transaction.
selfP2WKH, err := commitScriptUnencumbered(keyRing.NoDelayKey)
if err != nil {
return nil, fmt.Errorf("unable to create self commit script: %v", err)
}
var selfPoint *wire.OutPoint
for outputIndex, txOut := range commitTxBroadcast.TxOut {
if bytes.Equal(txOut.PkScript, selfP2WKH) {
selfPoint = &wire.OutPoint{
Hash: *commitSpend.SpenderTxHash,
Index: uint32(outputIndex),
}
break
}
}
// 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 commitResolution *CommitOutputResolution
if selfPoint != nil {
localPayBase := chanState.LocalChanCfg.PaymentBasePoint
localBalance := remoteCommit.LocalBalance.ToSatoshis()
commitResolution = &CommitOutputResolution{
SelfOutPoint: *selfPoint,
SelfOutputSignDesc: SignDescriptor{
PubKey: localPayBase,
SingleTweak: keyRing.LocalCommitKeyTweak,
WitnessScript: selfP2WKH,
Output: &wire.TxOut{
Value: int64(localBalance),
PkScript: selfP2WKH,
},
HashType: txscript.SigHashAll,
},
MaturityDelay: 0,
}
}
localBalance := remoteCommit.LocalBalance.ToSatoshis()
closeSummary := channeldb.ChannelCloseSummary{
ChanPoint: chanState.FundingOutpoint,
ChainHash: chanState.ChainHash,
ClosingTXID: *commitSpend.SpenderTxHash,
CloseHeight: uint32(commitSpend.SpendingHeight),
RemotePub: chanState.IdentityPub,
Capacity: chanState.Capacity,
SettledBalance: localBalance,
CloseType: channeldb.ForceClose,
IsPending: true,
}
return &UnilateralCloseSummary{
SpendDetail: commitSpend,
ChannelCloseSummary: closeSummary,
CommitResolution: commitResolution,
HtlcResolutions: htlcResolutions,
RemoteCommit: remoteCommit,
}, nil
}
// IncomingHtlcResolution houses the information required to sweep any incoming

@ -4184,26 +4184,18 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) {
// We'll then use Bob's transaction to trigger a spend notification for
// Alice.
aliceNotifier := aliceChannel.channelEvents.(*mockNotfier)
closeTx := bobForceClose.CloseTx
commitTxHash := closeTx.TxHash()
select {
case aliceNotifier.activeSpendNtfn <- &chainntnfs.SpendDetail{
spendDetail := &chainntnfs.SpendDetail{
SpendingTx: closeTx,
SpenderTxHash: &commitTxHash,
}:
case <-time.After(time.Second * 15):
t.Fatalf("alice didn't consume spend ntfn")
}
// Alice should now send over a signal on the unilateral close signal
// that we'll use to ensure she's able to sweep all the relevant
// outputs.
var aliceCloseSummary *UnilateralCloseSummary
select {
case aliceCloseSummary = <-aliceChannel.UnilateralClose:
case <-time.After(time.Second * 15):
t.Fatalf("alice didn't send her close summary")
aliceCloseSummary, err := NewUnilateralCloseSummary(
aliceChannel.channelState, aliceChannel.signer, aliceChannel.pCache,
spendDetail, aliceChannel.channelState.RemoteCommitment,
)
if err != nil {
t.Fatalf("unable to create alice close summary: %v", err)
}
// She should detect that she can sweep both the outgoing HTLC as well