lnwallet: add new createCommitDiff method

This commit adds a new method: createCommitDiff. The method will, given
a newly constructed commitment, its signature, and HTLC signatures will
create a channeldb.CommitDiff. The CommitDiff created is to be stored
on disk, as it can be used in the case that the remote party didn’t
receive our CommitSig message and also forgot all the updates that we
queued with the update.
This commit is contained in:
Olaoluwa Osuntokun 2017-11-09 22:55:38 -08:00
parent e50b3e6517
commit 611412bab0
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -1662,7 +1662,7 @@ type BreachRetribution struct {
// PendingHTLCs is a slice of the HTLCs which were pending at this // PendingHTLCs is a slice of the HTLCs which were pending at this
// point within the channel's history transcript. // point within the channel's history transcript.
PendingHTLCs []*channeldb.HTLC PendingHTLCs []channeldb.HTLC
// LocalOutputSignDesc is a SignDescriptor which is capable of // LocalOutputSignDesc is a SignDescriptor which is capable of
// generating the signature necessary to sweep the output within the // generating the signature necessary to sweep the output within the
@ -2720,55 +2720,102 @@ func genRemoteHtlcSigJobs(keyRing *commitmentKeyRing,
return sigBatch, cancelChan, nil return sigBatch, cancelChan, nil
} }
// createCommitDiff // createCommitDiff will create a commit diff given a new pending commitment
func (lc *LightningChannel) createCommitDiff(commitment *commitment) (*channeldb.CommitDiff, // for the remote party and the necessary signatures for the remote party to
error) { // validate this new state. This function is called right before sending the
// new commitment to the remote party. The commit diff returned contains all
// information necessary for retransmission.
func (lc *LightningChannel) createCommitDiff(
newCommit *commitment, commitSig *btcec.Signature,
htlcSigs []*btcec.Signature) (*channeldb.CommitDiff, error) {
// First, we need to convert the funding outpoint into the ID that's
// used on the wire to identify this channel. We'll use this shortly
// when recording the exact CommitSig message that we'll be sending
// out.
chanID := lnwire.NewChanIDFromOutPoint(&lc.channelState.FundingOutpoint) chanID := lnwire.NewChanIDFromOutPoint(&lc.channelState.FundingOutpoint)
var htlcs []lnwire.Message
// We'll now run through our local update log to locate the items which
// were only just committed within this pending state. This will be the
// set of items we need to retransmit if we reconnect and find that
// they didn't process this new state fully.
var logUpdates []channeldb.LogUpdate
for e := lc.localUpdateLog.Front(); e != nil; e = e.Next() { for e := lc.localUpdateLog.Front(); e != nil; e = e.Next() {
pd := e.Value.(*PaymentDescriptor) pd := e.Value.(*PaymentDescriptor)
// ... // If this entry wasn't committed at the exact height of this
var htlc lnwire.Message // remote commitment, then we'll skip it as it was already
if pd.addCommitHeightRemote == commitment.height { // lingering in the log.
switch pd.EntryType { if pd.addCommitHeightRemote != newCommit.height &&
case Add: pd.removeCommitHeightRemote != newCommit.height {
continue
case Settle: continue
htlc = &lnwire.UpdateFufillHTLC{ }
ChanID: chanID,
ID: pd.Index, // Knowing that this update is a part of this new commitment,
PaymentPreimage: pd.RPreimage, // we'll create a log update and not it's index in the log so
} // we can later restore it properly if a restart occurs.
case Fail: logUpdate := channeldb.LogUpdate{
htlc = &lnwire.UpdateFailHTLC{ LogIndex: pd.LogIndex,
ChanID: chanID, }
ID: pd.Index,
Reason: pd.FailReason, // We'll map the type of the PaymentDescriptor to one of the
} // four messages that it corresponds to. With this set of
case MalformedFail: // messages obtained, we can simply read from disk and re-send
htlc = &lnwire.UpdateFailMalformedHTLC{ // them in the case of a needed channel sync.
ChanID: chanID, switch pd.EntryType {
ID: pd.Index, case Add:
ShaOnionBlob: pd.ShaOnionBlob, htlc := &lnwire.UpdateAddHTLC{
FailureCode: pd.FailCode, ChanID: chanID,
} ID: pd.HtlcIndex,
Amount: pd.Amount,
Expiry: pd.Timeout,
PaymentHash: pd.RHash,
}
copy(htlc.OnionBlob[:], pd.OnionBlob)
logUpdate.UpdateMsg = htlc
case Settle:
logUpdate.UpdateMsg = &lnwire.UpdateFufillHTLC{
ChanID: chanID,
ID: pd.ParentIndex,
PaymentPreimage: pd.RPreimage,
} }
htlcs = append(htlcs, htlc) case Fail:
logUpdate.UpdateMsg = &lnwire.UpdateFailHTLC{
ChanID: chanID,
ID: pd.ParentIndex,
Reason: pd.FailReason,
}
case MalformedFail:
logUpdate.UpdateMsg = &lnwire.UpdateFailMalformedHTLC{
ChanID: chanID,
ID: pd.ParentIndex,
ShaOnionBlob: pd.ShaOnionBlob,
FailureCode: pd.FailCode,
}
} }
logUpdates = append(logUpdates, logUpdate)
} }
delta, err := commitment.toChannelDelta(false) // With the set of log updates mapped into wire messages, we'll now
if err != nil { // convert the in-memory commit into a format suitable for writing to
return nil, err // disk.
} diskCommit := newCommit.toDiskCommit(false)
return &channeldb.CommitDiff{ return &channeldb.CommitDiff{
PendingHeight: commitment.height, Commitment: *diskCommit,
PendingCommitment: delta, CommitSig: &lnwire.CommitSig{
Updates: htlcs, ChanID: lnwire.NewChanIDFromOutPoint(
&lc.channelState.FundingOutpoint,
),
CommitSig: commitSig,
HtlcSigs: htlcSigs,
},
LogUpdates: logUpdates,
}, nil }, nil
} }