lnwallet: Change channel update methods to accept HTLC ID.

Previously, some methods on a LightningChannel like SettleHTLC and
FailHTLC would identify HTLCs by payment hash. This would not always
work correctly if there are multiple HTLCs with the same payment hash,
so instead we change these methods to identify HTLCs by their unique
identifiers instead.
This commit is contained in:
Jim Posen 2017-10-24 00:48:52 -07:00 committed by Olaoluwa Osuntokun
parent 1328e61c00
commit 317b44e220
4 changed files with 181 additions and 140 deletions

View File

@ -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,
})

View File

@ -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,

View File

@ -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

View File

@ -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)
}