diff --git a/htlcswitch/link.go b/htlcswitch/link.go index c04ef158..15a96d48 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -743,8 +743,7 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket, isReProcess bool) { // An HTLC we forward to the switch has just settled somewhere // upstream. Therefore we settle the HTLC within the our local // state machine. - pre := htlc.PaymentPreimage - logIndex, _, err := l.channel.SettleHTLC(pre) + err := l.channel.SettleHTLC(htlc.PaymentPreimage, pkt.destID) if err != nil { // TODO(roasbeef): broadcast on-chain l.fail("unable to settle incoming HTLC: %v", err) @@ -755,7 +754,7 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket, isReProcess bool) { // message to target the specific channel and HTLC to be // cancelled. htlc.ChanID = l.ChanID() - htlc.ID = logIndex + htlc.ID = pkt.destID // Then we send the HTLC settle message to the connected peer // so we can continue the propagation of the settle message. @@ -765,7 +764,7 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket, isReProcess bool) { case *lnwire.UpdateFailHTLC: // An HTLC cancellation has been triggered somewhere upstream, // we'll remove then HTLC from our local state machine. - logIndex, err := l.channel.FailHTLC(pkt.payHash, htlc.Reason) + err := l.channel.FailHTLC(pkt.destID, htlc.Reason) if err != nil { log.Errorf("unable to cancel HTLC: %v", err) return @@ -776,7 +775,7 @@ func (l *channelLink) handleDownStreamPkt(pkt *htlcPacket, isReProcess bool) { // cancelled. The "Reason" field will have already been set // within the switch. htlc.ChanID = l.ChanID() - htlc.ID = logIndex + htlc.ID = pkt.destID // Finally, we send the HTLC message to the peer which // initially created the HTLC. @@ -891,7 +890,7 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { // If remote side have been unable to parse the onion blob we // have sent to it, than we should transform the malformed HTLC // message to the usual HTLC fail message. - _, err := l.channel.ReceiveFailHTLC(msg.ID, b.Bytes()) + err := l.channel.ReceiveFailHTLC(msg.ID, b.Bytes()) if err != nil { l.fail("unable to handle upstream fail HTLC: %v", err) return @@ -899,7 +898,7 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) { case *lnwire.UpdateFailHTLC: idx := msg.ID - _, err := l.channel.ReceiveFailHTLC(idx, msg.Reason[:]) + err := l.channel.ReceiveFailHTLC(idx, msg.Reason[:]) if err != nil { l.fail("unable to handle upstream fail HTLC: %v", err) return @@ -1219,7 +1218,7 @@ func (l *channelLink) processLockedInHtlcs( // continue to propagate it. failPacket := &htlcPacket{ src: l.ShortChanID(), - srcID: pd.HtlcIndex, + srcID: pd.ParentIndex, payHash: pd.RHash, amount: pd.Amount, isObfuscated: false, @@ -1256,7 +1255,7 @@ func (l *channelLink) processLockedInHtlcs( // If we're unable to process the onion blob // than we should send the malformed htlc error // to payment sender. - l.sendMalformedHTLCError(pd.RHash, failureCode, + l.sendMalformedHTLCError(pd.HtlcIndex, failureCode, onionBlob[:]) needUpdate = true @@ -1284,7 +1283,7 @@ func (l *channelLink) processLockedInHtlcs( // If we're unable to process the onion blob // than we should send the malformed htlc error // to payment sender. - l.sendMalformedHTLCError(pd.RHash, failureCode, + l.sendMalformedHTLCError(pd.HtlcIndex, failureCode, onionBlob[:]) needUpdate = true @@ -1309,7 +1308,7 @@ func (l *channelLink) processLockedInHtlcs( pd.Timeout, heightNow) failure := lnwire.FailFinalIncorrectCltvExpiry{} - l.sendHTLCError(pd.RHash, &failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, &failure, obfuscator) needUpdate = true continue } @@ -1324,7 +1323,7 @@ func (l *channelLink) processLockedInHtlcs( log.Errorf("unable to query invoice registry: "+ " %v", err) failure := lnwire.FailUnknownPaymentHash{} - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1340,7 +1339,7 @@ func (l *channelLink) processLockedInHtlcs( "amount: expected %v, received %v", invoice.Terms.Value, pd.Amount) failure := lnwire.FailIncorrectPaymentAmount{} - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1360,7 +1359,7 @@ func (l *channelLink) processLockedInHtlcs( fwdInfo.AmountToForward) failure := lnwire.FailIncorrectPaymentAmount{} - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1382,7 +1381,7 @@ func (l *channelLink) processLockedInHtlcs( failure := lnwire.NewFinalIncorrectCltvExpiry( fwdInfo.OutgoingCTLV, ) - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue case pd.Timeout != fwdInfo.OutgoingCTLV: @@ -1394,7 +1393,7 @@ func (l *channelLink) processLockedInHtlcs( failure := lnwire.NewFinalIncorrectCltvExpiry( fwdInfo.OutgoingCTLV, ) - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1408,7 +1407,7 @@ func (l *channelLink) processLockedInHtlcs( } preimage := invoice.Terms.PaymentPreimage - logIndex, _, err := l.channel.SettleHTLC(preimage) + err = l.channel.SettleHTLC(preimage, pd.HtlcIndex) if err != nil { l.fail("unable to settle htlc: %v", err) return nil @@ -1427,7 +1426,7 @@ func (l *channelLink) processLockedInHtlcs( // notification about it remote peer. l.cfg.Peer.SendMessage(&lnwire.UpdateFufillHTLC{ ChanID: l.ChanID(), - ID: logIndex, + ID: pd.HtlcIndex, PaymentPreimage: preimage, }) needUpdate = true @@ -1456,7 +1455,7 @@ func (l *channelLink) processLockedInHtlcs( failure = lnwire.NewExpiryTooSoon(*update) } - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1483,7 +1482,7 @@ func (l *channelLink) processLockedInHtlcs( pd.Amount, *update) } - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1525,7 +1524,7 @@ func (l *channelLink) processLockedInHtlcs( *update) } - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1557,7 +1556,7 @@ func (l *channelLink) processLockedInHtlcs( failure := lnwire.NewIncorrectCltvExpiry( pd.Timeout, *update) - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1584,7 +1583,7 @@ func (l *channelLink) processLockedInHtlcs( "remaining route %v", err) failure := lnwire.NewTemporaryChannelFailure(nil) - l.sendHTLCError(pd.RHash, failure, obfuscator) + l.sendHTLCError(pd.HtlcIndex, failure, obfuscator) needUpdate = true continue } @@ -1616,8 +1615,8 @@ func (l *channelLink) processLockedInHtlcs( // sendHTLCError functions cancels HTLC and send cancel message back to the // peer from which HTLC was received. -func (l *channelLink) sendHTLCError(rHash [32]byte, failure lnwire.FailureMessage, - e ErrorEncrypter) { +func (l *channelLink) sendHTLCError(htlcIndex uint64, + failure lnwire.FailureMessage, e ErrorEncrypter) { reason, err := e.EncryptFirstHop(failure) if err != nil { @@ -1625,7 +1624,7 @@ func (l *channelLink) sendHTLCError(rHash [32]byte, failure lnwire.FailureMessag return } - index, err := l.channel.FailHTLC(rHash, reason) + err = l.channel.FailHTLC(htlcIndex, reason) if err != nil { log.Errorf("unable cancel htlc: %v", err) return @@ -1633,18 +1632,18 @@ func (l *channelLink) sendHTLCError(rHash [32]byte, failure lnwire.FailureMessag l.cfg.Peer.SendMessage(&lnwire.UpdateFailHTLC{ ChanID: l.ChanID(), - ID: index, + ID: htlcIndex, Reason: reason, }) } // sendMalformedHTLCError helper function which sends the malformed HTLC update // to the payment sender. -func (l *channelLink) sendMalformedHTLCError(rHash [32]byte, code lnwire.FailCode, - onionBlob []byte) { +func (l *channelLink) sendMalformedHTLCError(htlcIndex uint64, + code lnwire.FailCode, onionBlob []byte) { shaOnionBlob := sha256.Sum256(onionBlob) - index, err := l.channel.MalformedFailHTLC(rHash, code, shaOnionBlob) + err := l.channel.MalformedFailHTLC(htlcIndex, code, shaOnionBlob) if err != nil { log.Errorf("unable cancel htlc: %v", err) return @@ -1652,7 +1651,7 @@ func (l *channelLink) sendMalformedHTLCError(rHash [32]byte, code lnwire.FailCod l.cfg.Peer.SendMessage(&lnwire.UpdateFailMalformedHTLC{ ChanID: l.ChanID(), - ID: index, + ID: htlcIndex, ShaOnionBlob: shaOnionBlob, FailureCode: code, }) diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index c9a53e42..636518d7 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -1583,6 +1583,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { // remain unchanged (but Alice will need to pay the fee for the extra // HTLC). updateMsg := &lnwire.UpdateAddHTLC{ + ID: 0, Amount: htlcAmt, Expiry: 9, PaymentHash: htlc.PaymentHash, // Re-using the same payment hash. @@ -1607,6 +1608,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) { // Finally, we'll test the scenario of failing an HTLC received by the // remote node. This should result in no perceived bandwidth changes. htlcAdd := &lnwire.UpdateAddHTLC{ + ID: 1, Amount: htlcAmt, Expiry: 9, PaymentHash: htlc.PaymentHash, diff --git a/lnwallet/channel.go b/lnwallet/channel.go index d14fea1d..36e437eb 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -17,8 +17,6 @@ import ( "github.com/roasbeef/btcd/blockchain" "github.com/roasbeef/btcd/chaincfg/chainhash" - "encoding/hex" - "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/txscript" "github.com/roasbeef/btcd/wire" @@ -3895,6 +3893,11 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, err lc.Lock() defer lc.Unlock() + if htlc.ID != lc.remoteUpdateLog.htlcCounter { + return 0, fmt.Errorf("ID %d on HTLC add does not match expected next "+ + "ID %d", htlc.ID, lc.remoteUpdateLog.htlcCounter) + } + if err := lc.validateCommitmentSanity(lc.remoteUpdateLog.logIndex, lc.localUpdateLog.logIndex, true, false, true); err != nil { return 0, err @@ -3922,36 +3925,41 @@ func (lc *LightningChannel) ReceiveHTLC(htlc *lnwire.UpdateAddHTLC) (uint64, err // creating the corresponding wire message. In the case the supplied preimage // is invalid, an error is returned. Additionally, the value of the settled // HTLC is also returned. -func (lc *LightningChannel) SettleHTLC(preimage [32]byte) (uint64, - lnwire.MilliSatoshi, error) { +func (lc *LightningChannel) SettleHTLC(preimage [32]byte, htlcIndex uint64, +) error { + lc.Lock() defer lc.Unlock() - paymentHash := sha256.Sum256(preimage[:]) - targetHTLCs, ok := lc.rHashMap[paymentHash] - if !ok { - return 0, 0, fmt.Errorf("invalid payment hash(%v)", - hex.EncodeToString(paymentHash[:])) + htlc := lc.remoteUpdateLog.lookupHtlc(htlcIndex) + if htlc == nil { + return fmt.Errorf("No HTLC with ID %d in channel %v", htlcIndex, + lc.channelState.ShortChanID) + } + + if htlc.RHash != sha256.Sum256(preimage[:]) { + return fmt.Errorf("Invalid payment preimage %x for hash %x", + preimage[:], htlc.RHash[:]) } - targetHTLC := targetHTLCs[0] pd := &PaymentDescriptor{ - Amount: targetHTLC.Amount, + Amount: htlc.Amount, RPreimage: preimage, LogIndex: lc.localUpdateLog.logIndex, - ParentIndex: targetHTLC.HtlcIndex, + ParentIndex: htlcIndex, EntryType: Settle, } lc.localUpdateLog.appendUpdate(pd) + paymentHash := htlc.RHash lc.rHashMap[paymentHash][0] = nil lc.rHashMap[paymentHash] = lc.rHashMap[paymentHash][1:] if len(lc.rHashMap[paymentHash]) == 0 { delete(lc.rHashMap, paymentHash) } - return targetHTLC.HtlcIndex, targetHTLC.Amount, nil + return nil } // ReceiveHTLCSettle attempts to settle an existing outgoing HTLC indexed by an @@ -3962,15 +3970,15 @@ func (lc *LightningChannel) ReceiveHTLCSettle(preimage [32]byte, htlcIndex uint6 lc.Lock() defer lc.Unlock() - paymentHash := sha256.Sum256(preimage[:]) htlc := lc.localUpdateLog.lookupHtlc(htlcIndex) if htlc == nil { - return fmt.Errorf("non-existent log entry") + return fmt.Errorf("No HTLC with ID %d in channel %v", htlcIndex, + lc.channelState.ShortChanID) } - if !bytes.Equal(htlc.RHash[:], paymentHash[:]) { - return fmt.Errorf("invalid payment hash(%v)", - hex.EncodeToString(paymentHash[:])) + if htlc.RHash != sha256.Sum256(preimage[:]) { + return fmt.Errorf("Invalid payment preimage %x for hash %x", + preimage[:], htlc.RHash[:]) } pd := &PaymentDescriptor{ @@ -3990,22 +3998,20 @@ func (lc *LightningChannel) ReceiveHTLCSettle(preimage [32]byte, htlcIndex uint6 // 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 // _incoming_ HTLC. -// -// TODO(roasbeef): add value as well? -func (lc *LightningChannel) FailHTLC(rHash [32]byte, reason []byte) (uint64, error) { +func (lc *LightningChannel) FailHTLC(htlcIndex uint64, reason []byte) error { lc.Lock() defer lc.Unlock() - addEntries, ok := lc.rHashMap[rHash] - if !ok { - return 0, fmt.Errorf("unable to find HTLC to fail") + htlc := lc.remoteUpdateLog.lookupHtlc(htlcIndex) + if htlc == nil { + return fmt.Errorf("No HTLC with ID %d in channel %v", htlcIndex, + lc.channelState.ShortChanID) } - addEntry := addEntries[0] pd := &PaymentDescriptor{ - Amount: addEntry.Amount, - RHash: addEntry.RHash, - ParentIndex: addEntry.HtlcIndex, + Amount: htlc.Amount, + RHash: htlc.RHash, + ParentIndex: htlcIndex, LogIndex: lc.localUpdateLog.logIndex, EntryType: Fail, FailReason: reason, @@ -4013,34 +4019,36 @@ func (lc *LightningChannel) FailHTLC(rHash [32]byte, reason []byte) (uint64, err lc.localUpdateLog.appendUpdate(pd) + rHash := htlc.RHash lc.rHashMap[rHash][0] = nil lc.rHashMap[rHash] = lc.rHashMap[rHash][1:] if len(lc.rHashMap[rHash]) == 0 { delete(lc.rHashMap, rHash) } - return addEntry.HtlcIndex, nil + return nil } // MalformedFailHTLC attempts to fail a targeted HTLC by its payment hash, // 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 // in _incoming_ HTLC. -func (lc *LightningChannel) MalformedFailHTLC(rHash [32]byte, - failCode lnwire.FailCode, shaOnionBlob [sha256.Size]byte) (uint64, error) { +func (lc *LightningChannel) MalformedFailHTLC(htlcIndex uint64, + failCode lnwire.FailCode, shaOnionBlob [sha256.Size]byte) error { + lc.Lock() defer lc.Unlock() - addEntries, ok := lc.rHashMap[rHash] - if !ok { - return 0, fmt.Errorf("unable to find HTLC to fail") + htlc := lc.remoteUpdateLog.lookupHtlc(htlcIndex) + if htlc == nil { + return fmt.Errorf("No HTLC with ID %d in channel %v", htlcIndex, + lc.channelState.ShortChanID) } - addEntry := addEntries[0] pd := &PaymentDescriptor{ - Amount: addEntry.Amount, - RHash: addEntry.RHash, - ParentIndex: addEntry.HtlcIndex, + Amount: htlc.Amount, + RHash: htlc.RHash, + ParentIndex: htlcIndex, LogIndex: lc.localUpdateLog.logIndex, EntryType: MalformedFail, FailCode: failCode, @@ -4049,13 +4057,14 @@ func (lc *LightningChannel) MalformedFailHTLC(rHash [32]byte, lc.localUpdateLog.appendUpdate(pd) + rHash := htlc.RHash lc.rHashMap[rHash][0] = nil lc.rHashMap[rHash] = lc.rHashMap[rHash][1:] if len(lc.rHashMap[rHash]) == 0 { delete(lc.rHashMap, rHash) } - return addEntry.HtlcIndex, nil + return nil } // ReceiveFailHTLC attempts to cancel a targeted HTLC by its log index, @@ -4063,15 +4072,16 @@ func (lc *LightningChannel) MalformedFailHTLC(rHash [32]byte, // commitment update. This method should be called in response to the upstream // party cancelling an outgoing HTLC. The value of the failed HTLC is returned // along with an error indicating success. -func (lc *LightningChannel) ReceiveFailHTLC(htlcIndex uint64, - reason []byte) (lnwire.MilliSatoshi, error) { +func (lc *LightningChannel) ReceiveFailHTLC(htlcIndex uint64, reason []byte, +) error { lc.Lock() defer lc.Unlock() htlc := lc.localUpdateLog.lookupHtlc(htlcIndex) if htlc == nil { - return 0, fmt.Errorf("unable to find HTLC to fail") + return fmt.Errorf("No HTLC with ID %d in channel %v", htlcIndex, + lc.channelState.ShortChanID) } pd := &PaymentDescriptor{ @@ -4085,7 +4095,7 @@ func (lc *LightningChannel) ReceiveFailHTLC(htlcIndex uint64, lc.remoteUpdateLog.appendUpdate(pd) - return htlc.Amount, nil + return nil } // ChannelPoint returns the outpoint of the original funding transaction which diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 5b2a1421..cfa8a387 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -408,14 +408,15 @@ func calcStaticFee(numHTLCs int) btcutil.Amount { // createHTLC is a utility function for generating an HTLC with a given // preimage and a given amount. -func createHTLC(data int, amount lnwire.MilliSatoshi) (*lnwire.UpdateAddHTLC, [32]byte) { - preimage := bytes.Repeat([]byte{byte(data)}, 32) +func createHTLC(id int, amount lnwire.MilliSatoshi) (*lnwire.UpdateAddHTLC, [32]byte) { + preimage := bytes.Repeat([]byte{byte(id)}, 32) paymentHash := sha256.Sum256(preimage) var returnPreimage [32]byte copy(returnPreimage[:], preimage) return &lnwire.UpdateAddHTLC{ + ID: uint64(id), PaymentHash: paymentHash, Amount: amount, Expiry: uint32(5), @@ -468,10 +469,13 @@ func TestSimpleAddSettleWorkflow(t *testing.T) { // First Alice adds the outgoing HTLC to her local channel's state // update log. Then Alice sends this wire message over to Bob who adds // this htlc to his remote state update log. - if _, err := aliceChannel.AddHTLC(htlc); err != nil { + aliceHtlcIndex, err := aliceChannel.AddHTLC(htlc) + if err != nil { t.Fatalf("unable to add htlc: %v", err) } - if _, err := bobChannel.ReceiveHTLC(htlc); err != nil { + + bobHtlcIndex, err := bobChannel.ReceiveHTLC(htlc) + if err != nil { t.Fatalf("unable to recv htlc: %v", err) } @@ -596,11 +600,13 @@ func TestSimpleAddSettleWorkflow(t *testing.T) { // HTLC once he learns of the preimage. var preimage [32]byte copy(preimage[:], paymentPreimage) - settleIndex, _, err := bobChannel.SettleHTLC(preimage) + err = bobChannel.SettleHTLC(preimage, bobHtlcIndex) if err != nil { t.Fatalf("bob unable to settle inbound htlc: %v", err) } - if err := aliceChannel.ReceiveHTLCSettle(preimage, settleIndex); err != nil { + + err = aliceChannel.ReceiveHTLCSettle(preimage, aliceHtlcIndex) + if err != nil { t.Fatalf("alice unable to accept settle of outbound htlc: %v", err) } @@ -742,7 +748,7 @@ func TestCheckCommitTxSize(t *testing.T) { // Adding HTLCs and check that size stays in allowable estimation // error window. - for i := 1; i <= 10; i++ { + for i := 0; i <= 10; i++ { htlc, _ := createHTLC(i, lnwire.MilliSatoshi(1e7)) if _, err := aliceChannel.AddHTLC(htlc); err != nil { @@ -755,20 +761,21 @@ func TestCheckCommitTxSize(t *testing.T) { if err := forceStateTransition(aliceChannel, bobChannel); err != nil { t.Fatalf("unable to complete state update: %v", err) } - checkSize(aliceChannel, i) - checkSize(bobChannel, i) + checkSize(aliceChannel, i+1) + checkSize(bobChannel, i+1) } // Settle HTLCs and check that estimation is counting cost of settle // HTLCs properly. - for i := 10; i >= 1; i-- { + for i := 10; i >= 0; i-- { _, preimage := createHTLC(i, lnwire.MilliSatoshi(1e7)) - settleIndex, _, err := bobChannel.SettleHTLC(preimage) + err := bobChannel.SettleHTLC(preimage, uint64(i)) if err != nil { t.Fatalf("bob unable to settle inbound htlc: %v", err) } - err = aliceChannel.ReceiveHTLCSettle(preimage, settleIndex) + + err = aliceChannel.ReceiveHTLCSettle(preimage, uint64(i)) if err != nil { t.Fatalf("alice unable to accept settle of outbound htlc: %v", err) } @@ -776,8 +783,8 @@ func TestCheckCommitTxSize(t *testing.T) { if err := forceStateTransition(bobChannel, aliceChannel); err != nil { t.Fatalf("unable to complete state update: %v", err) } - checkSize(aliceChannel, i-1) - checkSize(bobChannel, i-1) + checkSize(aliceChannel, i) + checkSize(bobChannel, i) } } @@ -1059,22 +1066,24 @@ func TestForceCloseDustOutput(t *testing.T) { // Have Bobs' to-self output be below her dust limit and check // ForceCloseSummary again on both peers. htlc, preimage := createHTLC(0, bobAmount-htlcAmount) - if _, err := bobChannel.AddHTLC(htlc); err != nil { - t.Fatalf("bob unable to add htlc: %v", err) + bobHtlcIndex, err := bobChannel.AddHTLC(htlc) + if err != nil { + t.Fatalf("alice unable to add htlc: %v", err) } - if _, err := aliceChannel.ReceiveHTLC(htlc); err != nil { - t.Fatalf("alice unable to receive htlc: %v", err) + aliceHtlcIndex, err := aliceChannel.ReceiveHTLC(htlc) + if err != nil { + t.Fatalf("bob unable to receive htlc: %v", err) } if err := forceStateTransition(bobChannel, aliceChannel); err != nil { t.Fatalf("Can't update the channel state: %v", err) } // Settle HTLC and sign new commitment. - settleIndex, _, err := aliceChannel.SettleHTLC(preimage) + err = aliceChannel.SettleHTLC(preimage, aliceHtlcIndex) if err != nil { t.Fatalf("bob unable to settle inbound htlc: %v", err) } - err = bobChannel.ReceiveHTLCSettle(preimage, settleIndex) + err = bobChannel.ReceiveHTLCSettle(preimage, bobHtlcIndex) if err != nil { t.Fatalf("alice unable to accept settle of outbound htlc: %v", err) } @@ -1241,10 +1250,12 @@ func TestHTLCDustLimit(t *testing.T) { htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat) htlc, preimage := createHTLC(0, htlcAmount) - if _, err := aliceChannel.AddHTLC(htlc); err != nil { + aliceHtlcIndex, err := aliceChannel.AddHTLC(htlc) + if err != nil { t.Fatalf("alice unable to add htlc: %v", err) } - if _, err := bobChannel.ReceiveHTLC(htlc); err != nil { + bobHtlcIndex, err := bobChannel.ReceiveHTLC(htlc) + if err != nil { t.Fatalf("bob unable to receive htlc: %v", err) } if err := forceStateTransition(aliceChannel, bobChannel); err != nil { @@ -1273,11 +1284,11 @@ func TestHTLCDustLimit(t *testing.T) { } // Settle HTLC and create a new commitment state. - settleIndex, _, err := bobChannel.SettleHTLC(preimage) + err = bobChannel.SettleHTLC(preimage, bobHtlcIndex) if err != nil { t.Fatalf("bob unable to settle inbound htlc: %v", err) } - err = aliceChannel.ReceiveHTLCSettle(preimage, settleIndex) + err = aliceChannel.ReceiveHTLCSettle(preimage, aliceHtlcIndex) if err != nil { t.Fatalf("alice unable to accept settle of outbound htlc: %v", err) } @@ -1330,20 +1341,22 @@ func TestChannelBalanceDustLimit(t *testing.T) { htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat) htlc, preimage := createHTLC(0, htlcAmount) - if _, err := aliceChannel.AddHTLC(htlc); err != nil { + aliceHtlcIndex, err := aliceChannel.AddHTLC(htlc) + if err != nil { t.Fatalf("alice unable to add htlc: %v", err) } - if _, err := bobChannel.ReceiveHTLC(htlc); err != nil { + bobHtlcIndex, err := bobChannel.ReceiveHTLC(htlc) + if err != nil { t.Fatalf("bob unable to receive htlc: %v", err) } if err := forceStateTransition(aliceChannel, bobChannel); err != nil { t.Fatalf("state transition error: %v", err) } - settleIndex, _, err := bobChannel.SettleHTLC(preimage) + err = bobChannel.SettleHTLC(preimage, bobHtlcIndex) if err != nil { t.Fatalf("bob unable to settle inbound htlc: %v", err) } - err = aliceChannel.ReceiveHTLCSettle(preimage, settleIndex) + err = aliceChannel.ReceiveHTLCSettle(preimage, aliceHtlcIndex) if err != nil { t.Fatalf("alice unable to accept settle of outbound htlc: %v", err) } @@ -1392,6 +1405,7 @@ func TestStateUpdatePersistence(t *testing.T) { for i := 0; i < 3; i++ { rHash := sha256.Sum256(alicePreimage[:]) h := &lnwire.UpdateAddHTLC{ + ID: uint64(i), PaymentHash: rHash, Amount: htlcAmt, Expiry: uint32(10), @@ -1587,20 +1601,20 @@ func TestStateUpdatePersistence(t *testing.T) { // Now settle all the HTLCs, then force a state update. The state // update should succeed as both sides have identical. for i := 0; i < 3; i++ { - settleIndex, _, err := bobChannelNew.SettleHTLC(alicePreimage) + err := bobChannelNew.SettleHTLC(alicePreimage, uint64(i)) if err != nil { t.Fatalf("unable to settle htlc #%v: %v", i, err) } - err = aliceChannelNew.ReceiveHTLCSettle(alicePreimage, settleIndex) + err = aliceChannelNew.ReceiveHTLCSettle(alicePreimage, uint64(i)) if err != nil { t.Fatalf("unable to settle htlc#%v: %v", i, err) } } - settleIndex, _, err := aliceChannelNew.SettleHTLC(bobPreimage) + err = aliceChannelNew.SettleHTLC(bobPreimage, 0) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = bobChannelNew.ReceiveHTLCSettle(bobPreimage, settleIndex) + err = bobChannelNew.ReceiveHTLCSettle(bobPreimage, 0) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -1678,12 +1692,13 @@ func TestCancelHTLC(t *testing.T) { Amount: htlcAmt, Expiry: 10, } - paymentHash := htlc.PaymentHash - if _, err := aliceChannel.AddHTLC(htlc); err != nil { + aliceHtlcIndex, err := aliceChannel.AddHTLC(htlc) + if err != nil { t.Fatalf("unable to add alice htlc: %v", err) } - if _, err := bobChannel.ReceiveHTLC(htlc); err != nil { + bobHtlcIndex, err := bobChannel.ReceiveHTLC(htlc) + if err != nil { t.Fatalf("unable to add bob htlc: %v", err) } if err := forceStateTransition(aliceChannel, bobChannel); err != nil { @@ -1703,11 +1718,12 @@ func TestCancelHTLC(t *testing.T) { // Now, with the HTLC committed on both sides, trigger a cancellation // from Bob to Alice, removing the HTLC. - htlcCancelIndex, err := bobChannel.FailHTLC(paymentHash, []byte("failreason")) + err = bobChannel.FailHTLC(bobHtlcIndex, []byte("failreason")) if err != nil { t.Fatalf("unable to cancel HTLC: %v", err) } - if _, err := aliceChannel.ReceiveFailHTLC(htlcCancelIndex, []byte("bad")); err != nil { + err = aliceChannel.ReceiveFailHTLC(aliceHtlcIndex, []byte("bad")) + if err != nil { t.Fatalf("unable to recv htlc cancel: %v", err) } @@ -2452,10 +2468,12 @@ func TestChanSyncFullySynced(t *testing.T) { Amount: htlcAmt, Expiry: uint32(5), } - if _, err := aliceChannel.AddHTLC(htlc); err != nil { + aliceHtlcIndex, err := aliceChannel.AddHTLC(htlc) + if err != nil { t.Fatalf("unable to add htlc: %v", err) } - if _, err := bobChannel.ReceiveHTLC(htlc); err != nil { + bobHtlcIndex, err := bobChannel.ReceiveHTLC(htlc) + if err != nil { t.Fatalf("unable to recv htlc: %v", err) } @@ -2470,11 +2488,11 @@ func TestChanSyncFullySynced(t *testing.T) { // If bob settles the HTLC, and then initiates a state transition, they // should both still think that they're in sync. - settleIndex, _, err := bobChannel.SettleHTLC(paymentPreimage) + err = bobChannel.SettleHTLC(paymentPreimage, bobHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = aliceChannel.ReceiveHTLCSettle(paymentPreimage, settleIndex) + err = aliceChannel.ReceiveHTLCSettle(paymentPreimage, aliceHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -2573,9 +2591,12 @@ func TestChanSyncOweCommitment(t *testing.T) { OnionBlob: fakeOnionBlob, } - if _, err := bobChannel.AddHTLC(h); err != nil { + htlcIndex, err := bobChannel.AddHTLC(h) + if err != nil { t.Fatalf("unable to add bob's htlc: %v", err) } + + h.ID = htlcIndex if _, err := aliceChannel.ReceiveHTLC(h); err != nil { t.Fatalf("unable to recv bob's htlc: %v", err) } @@ -2594,11 +2615,11 @@ func TestChanSyncOweCommitment(t *testing.T) { // Next, Alice's settles all 3 HTLC's from Bob, and also adds a new // HTLC of her own. for i := 0; i < 3; i++ { - settleIndex, _, err := aliceChannel.SettleHTLC(bobPreimage) + err := aliceChannel.SettleHTLC(bobPreimage, uint64(i)) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = bobChannel.ReceiveHTLCSettle(bobPreimage, settleIndex) + err = bobChannel.ReceiveHTLCSettle(bobPreimage, uint64(i)) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -2613,10 +2634,12 @@ func TestChanSyncOweCommitment(t *testing.T) { Expiry: uint32(10), OnionBlob: fakeOnionBlob, } - if _, err := aliceChannel.AddHTLC(aliceHtlc); err != nil { + aliceHtlcIndex, err := aliceChannel.AddHTLC(aliceHtlc) + if err != nil { t.Fatalf("unable to add alice's htlc: %v", err) } - if _, err := bobChannel.ReceiveHTLC(aliceHtlc); err != nil { + bobHtlcIndex, err := bobChannel.ReceiveHTLC(aliceHtlc) + if err != nil { t.Fatalf("unable to recv alice's htlc: %v", err) } @@ -2815,11 +2838,11 @@ func TestChanSyncOweCommitment(t *testing.T) { // We'll conclude the test by having Bob settle Alice's HTLC, then // initiate a state transition. - settleIndex, _, err := bobChannel.SettleHTLC(alicePreimage) + err = bobChannel.SettleHTLC(alicePreimage, bobHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = aliceChannel.ReceiveHTLCSettle(alicePreimage, settleIndex) + err = aliceChannel.ReceiveHTLCSettle(alicePreimage, aliceHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -2880,10 +2903,12 @@ func TestChanSyncOweRevocation(t *testing.T) { Amount: htlcAmt, Expiry: uint32(10), } - if _, err := bobChannel.AddHTLC(bobHtlc); err != nil { + bobHtlcIndex, err := bobChannel.AddHTLC(bobHtlc) + if err != nil { t.Fatalf("unable to add bob's htlc: %v", err) } - if _, err := aliceChannel.ReceiveHTLC(bobHtlc); err != nil { + aliceHtlcIndex, err := aliceChannel.ReceiveHTLC(bobHtlc) + if err != nil { t.Fatalf("unable to recv bob's htlc: %v", err) } if err := forceStateTransition(bobChannel, aliceChannel); err != nil { @@ -2892,11 +2917,11 @@ func TestChanSyncOweRevocation(t *testing.T) { // Next, Alice will settle that single HTLC, the _begin_ the start of a // state transition. - settleIndex, _, err := aliceChannel.SettleHTLC(bobPreimage) + err = aliceChannel.SettleHTLC(bobPreimage, aliceHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = bobChannel.ReceiveHTLCSettle(bobPreimage, settleIndex) + err = bobChannel.ReceiveHTLCSettle(bobPreimage, bobHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -3064,10 +3089,12 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) { Amount: htlcAmt, Expiry: uint32(10), } - if _, err := bobChannel.AddHTLC(bobHtlc); err != nil { + bobHtlcIndex, err := bobChannel.AddHTLC(bobHtlc) + if err != nil { t.Fatalf("unable to add bob's htlc: %v", err) } - if _, err := aliceChannel.ReceiveHTLC(bobHtlc); err != nil { + aliceHtlcIndex, err := aliceChannel.ReceiveHTLC(bobHtlc) + if err != nil { t.Fatalf("unable to recv bob's htlc: %v", err) } if err := forceStateTransition(bobChannel, aliceChannel); err != nil { @@ -3076,11 +3103,11 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) { // Next, Alice will settle that incoming HTLC, then we'll start the // core of the test itself. - settleIndex, _, err := aliceChannel.SettleHTLC(bobPreimage) + err = aliceChannel.SettleHTLC(bobPreimage, aliceHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = bobChannel.ReceiveHTLCSettle(bobPreimage, settleIndex) + err = bobChannel.ReceiveHTLCSettle(bobPreimage, bobHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -3232,10 +3259,12 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) { Amount: htlcAmt, Expiry: uint32(10), } - if _, err := bobChannel.AddHTLC(bobHtlc); err != nil { + bobHtlcIndex, err := bobChannel.AddHTLC(bobHtlc) + if err != nil { t.Fatalf("unable to add bob's htlc: %v", err) } - if _, err := aliceChannel.ReceiveHTLC(bobHtlc); err != nil { + aliceHtlcIndex, err := aliceChannel.ReceiveHTLC(bobHtlc) + if err != nil { t.Fatalf("unable to recv bob's htlc: %v", err) } if err := forceStateTransition(bobChannel, aliceChannel); err != nil { @@ -3244,11 +3273,11 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) { // Next, Alice will settle that incoming HTLC, then we'll start the // core of the test itself. - settleIndex, _, err := aliceChannel.SettleHTLC(bobPreimage) + err = aliceChannel.SettleHTLC(bobPreimage, aliceHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = bobChannel.ReceiveHTLCSettle(bobPreimage, settleIndex) + err = bobChannel.ReceiveHTLCSettle(bobPreimage, bobHtlcIndex) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } @@ -3799,7 +3828,7 @@ func TestChanAvailableBandwidth(t *testing.T) { // transaction. htlcAmt = lnwire.NewMSatFromSatoshis(30000) for i := 0; i < numHtlcs; i++ { - htlc, preImage := createHTLC(i, htlcAmt) + htlc, preImage := createHTLC(numHtlcs+i, htlcAmt) if _, err := aliceChannel.AddHTLC(htlc); err != nil { t.Fatalf("unable to add htlc: %v", err) } @@ -3816,21 +3845,22 @@ func TestChanAvailableBandwidth(t *testing.T) { // the update log). for i := 0; i < (numHtlcs*2)-1; i++ { preImage := alicePreimages[i] - settleIndex, _, err := bobChannel.SettleHTLC(preImage) + err := bobChannel.SettleHTLC(preImage, uint64(i)) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } - err = aliceChannel.ReceiveHTLCSettle(preImage, settleIndex) + err = aliceChannel.ReceiveHTLCSettle(preImage, uint64(i)) if err != nil { t.Fatalf("unable to settle htlc: %v", err) } } - failHash := sha256.Sum256(alicePreimages[5][:]) - failIndex, err := bobChannel.FailHTLC(failHash, []byte("f")) + + htlcIndex := uint64((numHtlcs * 2) - 1) + err = bobChannel.FailHTLC(htlcIndex, []byte("f")) if err != nil { t.Fatalf("unable to cancel HTLC: %v", err) } - _, err = aliceChannel.ReceiveFailHTLC(failIndex, []byte("bad")) + err = aliceChannel.ReceiveFailHTLC(htlcIndex, []byte("bad")) if err != nil { t.Fatalf("unable to recv htlc cancel: %v", err) }