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:
2 files changed
+101
-15
No files matched your search
@@ -4048,6 +4048,100 @@ type UnilateralCloseSummary struct {
|
|||||||
// and also any incoming HTLC's that we know the pre-image to.
|
// and also any incoming HTLC's that we know the pre-image to.
|
||||||
HtlcResolutions *HtlcResolutions
|
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
|
// 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
|
// We'll then use Bob's transaction to trigger a spend notification for
|
||||||
// Alice.
|
// Alice.
|
||||||
aliceNotifier := aliceChannel.channelEvents.(*mockNotfier)
|
|
||||||
closeTx := bobForceClose.CloseTx
|
closeTx := bobForceClose.CloseTx
|
||||||
commitTxHash := closeTx.TxHash()
|
commitTxHash := closeTx.TxHash()
|
||||||
select {
|
spendDetail := &chainntnfs.SpendDetail{
|
||||||
case aliceNotifier.activeSpendNtfn <- &chainntnfs.SpendDetail{
|
|
||||||
SpendingTx: closeTx,
|
SpendingTx: closeTx,
|
||||||
SpenderTxHash: &commitTxHash,
|
SpenderTxHash: &commitTxHash,
|
||||||
}:
|
|
||||||
case <-time.After(time.Second * 15):
|
|
||||||
t.Fatalf("alice didn't consume spend ntfn")
|
|
||||||
}
|
}
|
||||||
|
aliceCloseSummary, err := NewUnilateralCloseSummary(
|
||||||
// Alice should now send over a signal on the unilateral close signal
|
aliceChannel.channelState, aliceChannel.signer, aliceChannel.pCache,
|
||||||
// that we'll use to ensure she's able to sweep all the relevant
|
spendDetail, aliceChannel.channelState.RemoteCommitment,
|
||||||
// outputs.
|
)
|
||||||
var aliceCloseSummary *UnilateralCloseSummary
|
if err != nil {
|
||||||
select {
|
t.Fatalf("unable to create alice close summary: %v", err)
|
||||||
case aliceCloseSummary = <-aliceChannel.UnilateralClose:
|
|
||||||
case <-time.After(time.Second * 15):
|
|
||||||
t.Fatalf("alice didn't send her close summary")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// She should detect that she can sweep both the outgoing HTLC as well
|
// She should detect that she can sweep both the outgoing HTLC as well
|
||||||
|
|||||||
Reference in new issue
Block a user