lnwallet/channel: expose API changes to channel state transitions

This commit is contained in:
Conner Fromknecht 2018-02-27 20:04:41 -08:00
parent 7bad5458d7
commit d420266911
No known key found for this signature in database
GPG Key ID: 39DE78FBE6ACB0EF

@ -224,21 +224,21 @@ type PaymentDescriptor struct {
// link's commitment txn. // link's commitment txn.
DestRef *channeldb.SettleFailRef DestRef *channeldb.SettleFailRef
// OpenCircuitRef references the incoming Chan/HTLC ID of an Add HTLC // OpenCircuitKey references the incoming Chan/HTLC ID of an Add HTLC
// packet delivered by the switch. // packet delivered by the switch.
// //
// NOTE: This field is only populated for payment descriptors in the // NOTE: This field is only populated for payment descriptors in the
// *local* update log, and if the Add packet was delivered by the // *local* update log, and if the Add packet was delivered by the
// switch. // switch.
OpenCircuitRef *channeldb.CircuitKey OpenCircuitKey *channeldb.CircuitKey
// ClosedCircuitRef references the incoming Chan/HTLC ID of the Add HTLC // ClosedCircuitKey references the incoming Chan/HTLC ID of the Add HTLC
// that opened the circuit. // that opened the circuit.
// //
// NOTE: This field is only populated for payment descriptors in the // NOTE: This field is only populated for payment descriptors in the
// *local* update log, and if settle/fails have a committed circuit in // *local* update log, and if settle/fails have a committed circuit in
// the circuit map. // the circuit map.
ClosedCircuitRef *channeldb.CircuitKey ClosedCircuitKey *channeldb.CircuitKey
// localOutputIndex is the output index of this HTLc output in the // localOutputIndex is the output index of this HTLc output in the
// commitment transaction of the local node. // commitment transaction of the local node.
@ -327,12 +327,9 @@ type PaymentDescriptor struct {
// //
// NOTE: The provided `logUpdates` MUST corresponding exactly to either the Adds // NOTE: The provided `logUpdates` MUST corresponding exactly to either the Adds
// or SettleFails in this channel's forwarding package at `height`. // or SettleFails in this channel's forwarding package at `height`.
func (lc *LightningChannel) PayDescsFromRemoteLogUpdates(height uint64, func PayDescsFromRemoteLogUpdates(chanID lnwire.ShortChannelID, height uint64,
logUpdates []channeldb.LogUpdate) []*PaymentDescriptor { logUpdates []channeldb.LogUpdate) []*PaymentDescriptor {
lc.RLock()
defer lc.RUnlock()
// Allocate enough space to hold all of the payment descriptors we will // Allocate enough space to hold all of the payment descriptors we will
// reconstruct, and also the list of pointers that will be returned to // reconstruct, and also the list of pointers that will be returned to
// the caller. // the caller.
@ -373,7 +370,7 @@ func (lc *LightningChannel) PayDescsFromRemoteLogUpdates(height uint64,
ParentIndex: wireMsg.ID, ParentIndex: wireMsg.ID,
EntryType: Settle, EntryType: Settle,
DestRef: &channeldb.SettleFailRef{ DestRef: &channeldb.SettleFailRef{
Source: lc.ShortChanID(), Source: chanID,
Height: height, Height: height,
Index: uint16(i), Index: uint16(i),
}, },
@ -385,7 +382,7 @@ func (lc *LightningChannel) PayDescsFromRemoteLogUpdates(height uint64,
EntryType: Fail, EntryType: Fail,
FailReason: wireMsg.Reason[:], FailReason: wireMsg.Reason[:],
DestRef: &channeldb.SettleFailRef{ DestRef: &channeldb.SettleFailRef{
Source: lc.ShortChanID(), Source: chanID,
Height: height, Height: height,
Index: uint16(i), Index: uint16(i),
}, },
@ -398,7 +395,7 @@ func (lc *LightningChannel) PayDescsFromRemoteLogUpdates(height uint64,
FailCode: wireMsg.FailureCode, FailCode: wireMsg.FailureCode,
ShaOnionBlob: wireMsg.ShaOnionBlob, ShaOnionBlob: wireMsg.ShaOnionBlob,
DestRef: &channeldb.SettleFailRef{ DestRef: &channeldb.SettleFailRef{
Source: lc.ShortChanID(), Source: chanID,
Height: height, Height: height,
Index: uint16(i), Index: uint16(i),
}, },
@ -2741,9 +2738,9 @@ func (lc *LightningChannel) createCommitDiff(
// Gather any references for circuits opened by this Add // Gather any references for circuits opened by this Add
// HTLC. // HTLC.
if pd.OpenCircuitRef != nil { if pd.OpenCircuitKey != nil {
openCircuitKeys = append(openCircuitKeys, openCircuitKeys = append(openCircuitKeys,
*pd.OpenCircuitRef) *pd.OpenCircuitKey)
} }
logUpdates = append(logUpdates, logUpdate) logUpdates = append(logUpdates, logUpdate)
@ -2784,9 +2781,9 @@ func (lc *LightningChannel) createCommitDiff(
if pd.DestRef != nil { if pd.DestRef != nil {
settleFailRefs = append(settleFailRefs, *pd.DestRef) settleFailRefs = append(settleFailRefs, *pd.DestRef)
} }
if pd.ClosedCircuitRef != nil { if pd.ClosedCircuitKey != nil {
closedCircuitKeys = append(closedCircuitKeys, closedCircuitKeys = append(closedCircuitKeys,
*pd.ClosedCircuitRef) *pd.ClosedCircuitKey)
} }
logUpdates = append(logUpdates, logUpdate) logUpdates = append(logUpdates, logUpdate)
@ -2991,8 +2988,16 @@ func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, erro
// have not received // have not received
// * RevokeAndAck: if we sent a revocation message that they claim to have // * RevokeAndAck: if we sent a revocation message that they claim to have
// not received // not received
//
// If we detect a scenario where we need to send a CommitSig+Updates, this
// method also returns two sets channeldb.CircuitKeys identifying the circuits
// that were opened and closed, respectively, as a result of signing the
// previous commitment txn. This allows the link to clear its mailbox of those
// circuits in case they are still in memory, and ensure the switch's circuit
// map has been updated by deleting the closed circuits.
func (lc *LightningChannel) ProcessChanSyncMsg( func (lc *LightningChannel) ProcessChanSyncMsg(
msg *lnwire.ChannelReestablish) ([]lnwire.Message, error) { msg *lnwire.ChannelReestablish) ([]lnwire.Message, []channeldb.CircuitKey,
[]channeldb.CircuitKey, error) {
// We owe them a commitment if they have an un-acked commitment and the // We owe them a commitment if they have an un-acked commitment and the
// tip of their chain (from our Pov) is equal to what they think their // tip of their chain (from our Pov) is equal to what they think their
@ -3011,11 +3016,9 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// batch of messages which when applied will kick start the chain // batch of messages which when applied will kick start the chain
// resync. // resync.
var ( var (
updates []lnwire.Message updates []lnwire.Message
// TODO(conner): uncomment after API exposes these return openedCircuits []channeldb.CircuitKey
// variables, this permits compilation in the meantime closedCircuits []channeldb.CircuitKey
//openedCircuits []channeldb.CircuitKey
//closedCircuits []channeldb.CircuitKey
) )
// If the remote party included the optional fields, then we'll verify // If the remote party included the optional fields, then we'll verify
@ -3030,7 +3033,7 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
msg.RemoteCommitTailHeight - 1, msg.RemoteCommitTailHeight - 1,
) )
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
commitSecretCorrect = bytes.Equal( commitSecretCorrect = bytes.Equal(
heightSecret[:], msg.LastRemoteCommitSecret[:], heightSecret[:], msg.LastRemoteCommitSecret[:],
@ -3045,7 +3048,7 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// In this case, we'll return an error to indicate the remote // In this case, we'll return an error to indicate the remote
// node sent us the wrong values. This will let the caller act // node sent us the wrong values. This will let the caller act
// accordingly. // accordingly.
return nil, ErrInvalidLastCommitSecret return nil, nil, nil, ErrInvalidLastCommitSecret
} }
switch { switch {
@ -3057,7 +3060,7 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
localChainTail.height - 1, localChainTail.height - 1,
) )
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
updates = append(updates, revocationMsg) updates = append(updates, revocationMsg)
@ -3092,7 +3095,7 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// Otherwise, this is an error and we'll treat it as // Otherwise, this is an error and we'll treat it as
// such. // such.
default: default:
return nil, err return nil, nil, nil, err
} }
} }
@ -3105,17 +3108,17 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// In this case, we've likely lost data and shouldn't proceed // In this case, we've likely lost data and shouldn't proceed
// with channel updates. So we'll return the appropriate error // with channel updates. So we'll return the appropriate error
// to signal to the caller the current state. // to signal to the caller the current state.
return nil, ErrCommitSyncDataLoss return nil, nil, nil, ErrCommitSyncDataLoss
// If we don't owe them a revocation, and the height of our commitment // If we don't owe them a revocation, and the height of our commitment
// chain reported by the remote party is not equal to our chain tail, // chain reported by the remote party is not equal to our chain tail,
// then we cannot sync. // then we cannot sync.
case !oweRevocation && localChainTail.height != msg.RemoteCommitTailHeight: case !oweRevocation && localChainTail.height != msg.RemoteCommitTailHeight:
if err := lc.channelState.MarkBorked(); err != nil { if err := lc.channelState.MarkBorked(); err != nil {
return nil, err return nil, nil, nil, err
} }
return nil, ErrCannotSyncCommitChains return nil, nil, nil, ErrCannotSyncCommitChains
} }
// If we owe them a commitment, then we'll read from disk our // If we owe them a commitment, then we'll read from disk our
@ -3126,7 +3129,7 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// our states. // our states.
commitDiff, err := lc.channelState.RemoteCommitChainTip() commitDiff, err := lc.channelState.RemoteCommitChainTip()
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
// Next, we'll need to send over any updates we sent as part of // Next, we'll need to send over any updates we sent as part of
@ -3140,23 +3143,21 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
// commitment chain with our local version of their chain. // commitment chain with our local version of their chain.
updates = append(updates, commitDiff.CommitSig) updates = append(updates, commitDiff.CommitSig)
// TODO(conner): uncomment after API exposes these return openedCircuits = commitDiff.OpenedCircuitKeys
// variables, this permits compilation in the meantime closedCircuits = commitDiff.ClosedCircuitKeys
//openedCircuits = commitDiff.OpenedCircuitKeys
//closedCircuits = commitDiff.ClosedCircuitKeys
} else if remoteChainTip.height+1 != msg.NextLocalCommitHeight { } else if remoteChainTip.height+1 != msg.NextLocalCommitHeight {
if err := lc.channelState.MarkBorked(); err != nil { if err := lc.channelState.MarkBorked(); err != nil {
return nil, err return nil, nil, nil, err
} }
// If we don't owe them a commitment, yet the tip of their // If we don't owe them a commitment, yet the tip of their
// chain isn't one more than the next local commit height they // chain isn't one more than the next local commit height they
// report, we'll fail the channel. // report, we'll fail the channel.
return nil, ErrCannotSyncCommitChains return nil, nil, nil, ErrCannotSyncCommitChains
} }
return updates, nil return updates, openedCircuits, closedCircuits, nil
} }
// ChanSyncMsg returns the ChannelReestablish message that should be sent upon // ChanSyncMsg returns the ChannelReestablish message that should be sent upon
@ -3859,10 +3860,17 @@ func (lc *LightningChannel) RevokeCurrentCommitment() (*lnwire.RevokeAndAck, []c
// revocation either during the initial session negotiation wherein revocation // revocation either during the initial session negotiation wherein revocation
// windows are extended, or in response to a state update that we initiate. If // windows are extended, or in response to a state update that we initiate. If
// successful, then the remote commitment chain is advanced by a single // successful, then the remote commitment chain is advanced by a single
// commitment, and a log compaction is attempted. In addition, a slice of // commitment, and a log compaction is attempted.
// HTLC's which can be forwarded upstream are returned. //
// The returned values correspond to:
// 1. The forwarding package corresponding to the remote commitment height
// that was revoked.
// 2. The PaymentDescriptor of any Add HTLCs that were locked in by this
// revocation.
// 3. The PaymentDescriptor of any Settle/Fail HTLCs that were locked in by
// this revocation.
func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) ( func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
[]*PaymentDescriptor, error) { *channeldb.FwdPkg, []*PaymentDescriptor, []*PaymentDescriptor, error) {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
@ -3871,10 +3879,10 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
store := lc.channelState.RevocationStore store := lc.channelState.RevocationStore
revocation, err := chainhash.NewHash(revMsg.Revocation[:]) revocation, err := chainhash.NewHash(revMsg.Revocation[:])
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
if err := store.AddNextEntry(revocation); err != nil { if err := store.AddNextEntry(revocation); err != nil {
return nil, err return nil, nil, nil, err
} }
// Verify that if we use the commitment point computed based off of the // Verify that if we use the commitment point computed based off of the
@ -3883,7 +3891,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
currentCommitPoint := lc.channelState.RemoteCurrentRevocation currentCommitPoint := lc.channelState.RemoteCurrentRevocation
derivedCommitPoint := ComputeCommitmentPoint(revMsg.Revocation[:]) derivedCommitPoint := ComputeCommitmentPoint(revMsg.Revocation[:])
if !derivedCommitPoint.IsEqual(currentCommitPoint) { if !derivedCommitPoint.IsEqual(currentCommitPoint) {
return nil, fmt.Errorf("revocation key mismatch") return nil, nil, nil, fmt.Errorf("revocation key mismatch")
} }
// Now that we've verified that the prior commitment has been properly // Now that we've verified that the prior commitment has been properly
@ -4048,7 +4056,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
// commitment chain. // commitment chain.
err = lc.channelState.AdvanceCommitChainTail(fwdPkg) err = lc.channelState.AdvanceCommitChainTail(fwdPkg)
if err != nil { if err != nil {
return nil, err return nil, nil, nil, err
} }
// Since they revoked the current lowest height in their commitment // Since they revoked the current lowest height in their commitment
@ -4061,10 +4069,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
compactLogs(lc.localUpdateLog, lc.remoteUpdateLog, compactLogs(lc.localUpdateLog, lc.remoteUpdateLog,
localChainTail, remoteChainTail) localChainTail, remoteChainTail)
htlcsToForward := append(settleFailsToForward, return fwdPkg, addsToForward, settleFailsToForward, nil
addsToForward...)
return htlcsToForward, nil
} }
// LoadFwdPkgs loads any pending log updates from disk and returns the payment // LoadFwdPkgs loads any pending log updates from disk and returns the payment
@ -4116,19 +4121,26 @@ func (lc *LightningChannel) InitNextRevocation(revKey *btcec.PublicKey) error {
// AddHTLC adds an HTLC to the state machine's local update log. This method // AddHTLC adds an HTLC to the state machine's local update log. This method
// should be called when preparing to send an outgoing HTLC. // should be called when preparing to send an outgoing HTLC.
func (lc *LightningChannel) AddHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, error) { //
// The additional openKey argument corresponds to the incoming CircuitKey of the
// committed circuit for this HTLC. This value should never be nil.
//
// NOTE: It is okay for sourceRef to be nil when unit testing the wallet.
func (lc *LightningChannel) AddHTLC(htlc *lnwire.UpdateAddHTLC,
openKey *channeldb.CircuitKey) (uint64, error) {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
pd := &PaymentDescriptor{ pd := &PaymentDescriptor{
EntryType: Add, EntryType: Add,
RHash: PaymentHash(htlc.PaymentHash), RHash: PaymentHash(htlc.PaymentHash),
Timeout: htlc.Expiry, Timeout: htlc.Expiry,
Amount: htlc.Amount, Amount: htlc.Amount,
LogIndex: lc.localUpdateLog.logIndex, LogIndex: lc.localUpdateLog.logIndex,
HtlcIndex: lc.localUpdateLog.htlcCounter, HtlcIndex: lc.localUpdateLog.htlcCounter,
OnionBlob: htlc.OnionBlob[:], OnionBlob: htlc.OnionBlob[:],
OpenCircuitKey: openKey,
} }
// Make sure adding this HTLC won't violate any of the constraints we // Make sure adding this HTLC won't violate any of the constraints we
@ -4176,9 +4188,29 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, err
// SettleHTLC attempts to settle an existing outstanding received HTLC. The // SettleHTLC attempts to settle an existing outstanding received HTLC. The
// remote log index of the HTLC settled is returned in order to facilitate // remote log index of the HTLC settled is returned in order to facilitate
// creating the corresponding wire message. In the case the supplied preimage // creating the corresponding wire message. In the case the supplied preimage
// is invalid, an error is returned. Additionally, the value of the settled // is invalid, an error is returned.
// HTLC is also returned. //
func (lc *LightningChannel) SettleHTLC(preimage [32]byte, htlcIndex uint64) error { // The additional arguments correspond to:
// * sourceRef: specifies the location of the Add HTLC within a forwarding
// package that this HTLC is settling. Every Settle fails exactly one Add,
// so this should never be empty in practice.
//
// * destRef: specifies the location of the Settle HTLC within another
// channel's forwarding package. This value can be nil if the corresponding
// Add HTLC was never locked into an outgoing commitment txn, or this
// HTLC does not originate as a response from the peer on the outgoing
// link, e.g. on-chain resolutions.
//
// * closeKey: identifies the circuit that should be deleted after this Settle
// HTLC is included in a commitment txn. This value should only be nil if
// the HTLC was settled locally before committing a circuit to the circuit
// map.
//
// NOTE: It is okay for sourceRef, destRef, and closeKey to be nil when unit
// testing the wallet.
func (lc *LightningChannel) SettleHTLC(preimage [32]byte,
htlcIndex uint64, sourceRef *channeldb.AddRef,
destRef *channeldb.SettleFailRef, closeKey *channeldb.CircuitKey) error {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
@ -4195,11 +4227,14 @@ func (lc *LightningChannel) SettleHTLC(preimage [32]byte, htlcIndex uint64) erro
} }
pd := &PaymentDescriptor{ pd := &PaymentDescriptor{
Amount: htlc.Amount, Amount: htlc.Amount,
RPreimage: preimage, RPreimage: preimage,
LogIndex: lc.localUpdateLog.logIndex, LogIndex: lc.localUpdateLog.logIndex,
ParentIndex: htlcIndex, ParentIndex: htlcIndex,
EntryType: Settle, EntryType: Settle,
SourceRef: sourceRef,
DestRef: destRef,
ClosedCircuitKey: closeKey,
} }
lc.localUpdateLog.appendUpdate(pd) lc.localUpdateLog.appendUpdate(pd)
@ -4243,7 +4278,28 @@ func (lc *LightningChannel) ReceiveHTLCSettle(preimage [32]byte, htlcIndex uint6
// entry which will remove the target log entry within the next commitment // entry which will remove the target log entry within the next commitment
// update. This method is intended to be called in order to cancel in // update. This method is intended to be called in order to cancel in
// _incoming_ HTLC. // _incoming_ HTLC.
func (lc *LightningChannel) FailHTLC(htlcIndex uint64, reason []byte) error { //
// The additional arguments correspond to:
// * sourceRef: specifies the location of the Add HTLC within a forwarding
// package that this HTLC is failing. Every Fail fails exactly one Add, so
// this should never be empty in practice.
//
// * destRef: specifies the location of the Fail HTLC within another channel's
// forwarding package. This value can be nil if the corresponding Add HTLC
// was never locked into an outgoing commitment txn, or this HTLC does not
// originate as a response from the peer on the outgoing link, e.g.
// on-chain resolutions.
//
// * closeKey: identifies the circuit that should be deleted after this Fail
// HTLC is included in a commitment txn. This value should only be nil if
// the HTLC was failed locally before committing a circuit to the circuit
// map.
//
// NOTE: It is okay for sourceRef, destRef, and closeKey to be nil when unit
// testing the wallet.
func (lc *LightningChannel) FailHTLC(htlcIndex uint64, reason []byte,
sourceRef *channeldb.AddRef, destRef *channeldb.SettleFailRef,
closeKey *channeldb.CircuitKey) error {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
@ -4255,12 +4311,15 @@ func (lc *LightningChannel) FailHTLC(htlcIndex uint64, reason []byte) error {
} }
pd := &PaymentDescriptor{ pd := &PaymentDescriptor{
Amount: htlc.Amount, Amount: htlc.Amount,
RHash: htlc.RHash, RHash: htlc.RHash,
ParentIndex: htlcIndex, ParentIndex: htlcIndex,
LogIndex: lc.localUpdateLog.logIndex, LogIndex: lc.localUpdateLog.logIndex,
EntryType: Fail, EntryType: Fail,
FailReason: reason, FailReason: reason,
SourceRef: sourceRef,
DestRef: destRef,
ClosedCircuitKey: closeKey,
} }
lc.localUpdateLog.appendUpdate(pd) lc.localUpdateLog.appendUpdate(pd)
@ -4272,8 +4331,15 @@ func (lc *LightningChannel) FailHTLC(htlcIndex uint64, reason []byte) error {
// inserting an entry which will remove the target log entry within the next // inserting an entry which will remove the target log entry within the next
// commitment update. This method is intended to be called in order to cancel // commitment update. This method is intended to be called in order to cancel
// in _incoming_ HTLC. // in _incoming_ HTLC.
//
// The additional sourceRef specifies the location of the Add HTLC within a
// forwarding package that this HTLC is failing. This value should never be
// empty.
//
// NOTE: It is okay for sourceRef to be nil when unit testing the wallet.
func (lc *LightningChannel) MalformedFailHTLC(htlcIndex uint64, func (lc *LightningChannel) MalformedFailHTLC(htlcIndex uint64,
failCode lnwire.FailCode, shaOnionBlob [sha256.Size]byte) error { failCode lnwire.FailCode, shaOnionBlob [sha256.Size]byte,
sourceRef *channeldb.AddRef) error {
lc.Lock() lc.Lock()
defer lc.Unlock() defer lc.Unlock()
@ -4292,6 +4358,7 @@ func (lc *LightningChannel) MalformedFailHTLC(htlcIndex uint64,
EntryType: MalformedFail, EntryType: MalformedFail,
FailCode: failCode, FailCode: failCode,
ShaOnionBlob: shaOnionBlob, ShaOnionBlob: shaOnionBlob,
SourceRef: sourceRef,
} }
lc.localUpdateLog.appendUpdate(pd) lc.localUpdateLog.appendUpdate(pd)