htlcswitch/link_test: generate random preimages

This commit is contained in:
Conner Fromknecht 2018-01-16 00:37:15 -08:00
parent 101ad09e9f
commit 3a186a02a9
No known key found for this signature in database
GPG Key ID: 39DE78FBE6ACB0EF

@ -2,7 +2,10 @@ package htlcswitch
import (
"bytes"
"crypto/rand"
"encoding/binary"
"fmt"
"io"
"runtime"
"strings"
"sync"
@ -837,7 +840,7 @@ func TestUpdateForwardingPolicy(t *testing.T) {
ferr, ok := err.(*ForwardingError)
if !ok {
t.Fatalf("expected a ForwardingError, instead got: %T", err)
t.Fatalf("expected a ForwardingError, instead got (%T): %v", err, err)
}
switch ferr.FailureMessage.(type) {
case *lnwire.FailFeeInsufficient:
@ -1050,7 +1053,11 @@ func TestChannelLinkMultiHopUnknownNextHop(t *testing.T) {
htlcAmt, totalTimelock, hops := generateHops(amount, testStartingHeight,
n.firstBobChannelLink, n.carolChannelLink)
davePub := newMockServer(t, "dave").PubKey()
daveServer, err := newMockServer(t, "dave", nil)
if err != nil {
t.Fatalf("unable to init dave's server: %v", err)
}
davePub := daveServer.PubKey()
receiver := n.bobServer
rhash, err := n.makePayment(n.aliceServer, n.bobServer, davePub, hops,
amount, htlcAmt, totalTimelock).Wait(30 * time.Second)
@ -1412,7 +1419,14 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
},
}
chanID := lnwire.NewShortChanIDFromInt(4)
var chanIDBytes [8]byte
if _, err := io.ReadFull(rand.Reader, chanIDBytes[:]); err != nil {
return nil, nil, nil, nil, err
}
chanID := lnwire.NewShortChanIDFromInt(
binary.BigEndian.Uint64(chanIDBytes[:]))
aliceChannel, bobChannel, fCleanUp, _, err := createTestChannel(
alicePrivKey, bobPrivKey, chanAmt, chanAmt,
chanReserve, chanReserve, chanID,
@ -1423,8 +1437,8 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
var (
invoiceRegistry = newMockRegistry()
decoder = &mockIteratorDecoder{}
obfuscator = newMockObfuscator()
decoder = newMockIteratorDecoder()
obfuscator = NewMockObfuscator()
alicePeer = &mockPeer{
sentMsgs: make(chan lnwire.Message, 2000),
quit: make(chan struct{}),
@ -1442,14 +1456,25 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
preimageMap: make(map[[32]byte][]byte),
}
aliceDb := aliceChannel.State().Db
aliceSwitch, err := New(Config{DB: aliceDb})
if err != nil {
return nil, nil, nil, nil, err
}
t := make(chan time.Time)
ticker := &mockTicker{t}
aliceCfg := ChannelLinkConfig{
FwrdingPolicy: globalPolicy,
Peer: alicePeer,
Switch: New(Config{}),
DecodeHopIterator: decoder.DecodeHopIterator,
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (ErrorEncrypter, lnwire.FailCode) {
FwrdingPolicy: globalPolicy,
Peer: alicePeer,
Switch: aliceSwitch,
Circuits: aliceSwitch.CircuitModifier(),
ForwardPackets: aliceSwitch.ForwardPackets,
DecodeHopIterator: decoder.DecodeHopIterator,
DecodeHopIterators: decoder.DecodeHopIterators,
DecodeOnionObfuscator: func(*sphinx.OnionPacket) (
ErrorEncrypter, lnwire.FailCode) {
return obfuscator, lnwire.CodeNone
},
GetLastChannelUpdate: mockGetChanUpdateMessage,
@ -1457,10 +1482,11 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
UpdateContractSignals: func(*contractcourt.ContractSignals) error {
return nil
},
Registry: invoiceRegistry,
ChainEvents: &contractcourt.ChainEventSubscription{},
BlockEpochs: globalEpoch,
BatchTicker: ticker,
Registry: invoiceRegistry,
ChainEvents: &contractcourt.ChainEventSubscription{},
BlockEpochs: globalEpoch,
BatchTicker: ticker,
FwdPkgGCTicker: NewBatchTicker(time.NewTicker(5 * time.Second)),
// Make the BatchSize large enough to not
// trigger commit update automatically during tests.
BatchSize: 10000,
@ -1468,6 +1494,9 @@ func newSingleLinkTestHarness(chanAmt, chanReserve btcutil.Amount) (
const startingHeight = 100
aliceLink := NewChannelLink(aliceCfg, aliceChannel, startingHeight)
mailbox := newMemoryMailBox()
mailbox.Start()
aliceLink.AttachMailBox(mailbox)
if err := aliceLink.Start(); err != nil {
return nil, nil, nil, nil, err
}
@ -1659,25 +1688,27 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
// We'll start the test by creating a single instance of
const chanAmt = btcutil.SatoshiPerBitcoin * 5
link, bobChannel, tmr, cleanUp, err := newSingleLinkTestHarness(chanAmt, 0)
aliceLink, bobChannel, tmr, cleanUp, err := newSingleLinkTestHarness(chanAmt, 0)
if err != nil {
t.Fatalf("unable to create link: %v", err)
}
defer cleanUp()
var (
carolChanID = lnwire.NewShortChanIDFromInt(3)
mockBlob [lnwire.OnionPacketSize]byte
aliceLink = link.(*channelLink)
aliceChannel = aliceLink.channel
defaultCommitFee = aliceChannel.StateSnapshot().CommitFee
coreChan = aliceLink.(*channelLink).channel
coreLink = aliceLink.(*channelLink)
defaultCommitFee = coreChan.StateSnapshot().CommitFee
aliceStartingBandwidth = aliceLink.Bandwidth()
aliceMsgs = aliceLink.cfg.Peer.(*mockPeer).sentMsgs
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
)
// We put Alice into HodlHTLC mode, such that she won't settle
// incoming HTLCs automatically.
aliceLink.cfg.HodlHTLC = true
aliceLink.cfg.DebugHTLC = true
coreLink.cfg.HodlHTLC = true
coreLink.cfg.DebugHTLC = true
estimator := &lnwallet.StaticFeeEstimator{
FeeRate: 24,
@ -1705,9 +1736,22 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
t.Fatalf("unable to create payment: %v", err)
}
addPkt := htlcPacket{
htlc: htlc,
htlc: htlc,
incomingChanID: sourceHop,
incomingHTLCID: 0,
obfuscator: NewMockObfuscator(),
}
circuit := makePaymentCircuit(&htlc.PaymentHash, &addPkt)
_, err = coreLink.cfg.Switch.commitCircuits(&circuit)
if err != nil {
t.Fatalf("unable to commit circuit: %v", err)
}
addPkt.circuit = &circuit
if err := aliceLink.HandleSwitchPacket(&addPkt); err != nil {
t.Fatalf("unable to handle switch packet: %v", err)
}
aliceLink.HandleSwitchPacket(&addPkt)
time.Sleep(time.Millisecond * 500)
// The resulting bandwidth should reflect that Alice is paying the
@ -1733,10 +1777,9 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
}
// Lock in the HTLC.
if err := updateState(tmr, aliceLink, bobChannel, true); err != nil {
if err := updateState(tmr, coreLink, bobChannel, true); err != nil {
t.Fatalf("unable to update state: %v", err)
}
// Locking in the HTLC should not change Alice's bandwidth.
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
@ -1748,7 +1791,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
t.Fatalf("unable to settle htlc: %v", err)
}
htlcSettle := &lnwire.UpdateFulfillHTLC{
ID: bobIndex,
ID: 0,
PaymentPreimage: invoice.Terms.PaymentPreimage,
}
aliceLink.HandleChannelUpdate(htlcSettle)
@ -1759,7 +1802,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
// Lock in the settle.
if err := updateState(tmr, aliceLink, bobChannel, false); err != nil {
if err := updateState(tmr, coreLink, bobChannel, false); err != nil {
t.Fatalf("unable to update state: %v", err)
}
@ -1773,9 +1816,22 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
t.Fatalf("unable to create payment: %v", err)
}
addPkt = htlcPacket{
htlc: htlc,
htlc: htlc,
incomingChanID: sourceHop,
incomingHTLCID: 1,
obfuscator: NewMockObfuscator(),
}
circuit = makePaymentCircuit(&htlc.PaymentHash, &addPkt)
_, err = coreLink.cfg.Switch.commitCircuits(&circuit)
if err != nil {
t.Fatalf("unable to commit circuit: %v", err)
}
addPkt.circuit = &circuit
if err := aliceLink.HandleSwitchPacket(&addPkt); err != nil {
t.Fatalf("unable to handle switch packet: %v", err)
}
aliceLink.HandleSwitchPacket(&addPkt)
time.Sleep(time.Millisecond * 500)
// Again, Alice's bandwidth decreases by htlcAmt+htlcFee.
@ -1787,6 +1843,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
case <-time.After(2 * time.Second):
t.Fatalf("did not receive message")
}
addHtlc, ok = msg.(*lnwire.UpdateAddHTLC)
if !ok {
t.Fatalf("expected UpdateAddHTLC, got %T", msg)
@ -1798,7 +1855,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
}
// Lock in the HTLC, which should not affect the bandwidth.
if err := updateState(tmr, aliceLink, bobChannel, true); err != nil {
if err := updateState(tmr, coreLink, bobChannel, true); err != nil {
t.Fatalf("unable to update state: %v", err)
}
@ -1812,9 +1869,10 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
t.Fatalf("unable to fail htlc: %v", err)
}
failMsg := &lnwire.UpdateFailHTLC{
ID: bobIndex,
ID: 1,
Reason: lnwire.OpaqueReason([]byte("nop")),
}
aliceLink.HandleChannelUpdate(failMsg)
time.Sleep(time.Millisecond * 500)
@ -1822,7 +1880,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt*2-htlcFee)
// Lock in the Fail.
if err := updateState(tmr, aliceLink, bobChannel, false); err != nil {
if err := updateState(tmr, coreLink, bobChannel, false); err != nil {
t.Fatalf("unable to update state: %v", err)
}
@ -1834,7 +1892,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
// remain unchanged (but Alice will need to pay the fee for the extra
// HTLC).
htlcAmt, totalTimelock, hops := generateHops(htlcAmt, testStartingHeight,
aliceLink)
coreLink)
blob, err := generateRoute(hops...)
if err != nil {
t.Fatalf("unable to gen route: %v", err)
@ -1847,11 +1905,12 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
// We must add the invoice to the registry, such that Alice expects
// this payment.
err = aliceLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice(*invoice)
err = coreLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice(*invoice)
if err != nil {
t.Fatalf("unable to add invoice to registry: %v", err)
}
htlc.ID = 0
bobIndex, err = bobChannel.AddHTLC(htlc, nil)
if err != nil {
t.Fatalf("unable to add htlc: %v", err)
@ -1862,58 +1921,84 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt)
// Lock in the HTLC.
if err := updateState(tmr, aliceLink, bobChannel, false); err != nil {
if err := updateState(tmr, coreLink, bobChannel, false); err != nil {
t.Fatalf("unable to update state: %v", err)
}
// Since Bob is adding this HTLC, Alice only needs to pay the fee.
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
time.Sleep(time.Millisecond * 500)
addPkt = htlcPacket{
htlc: htlc,
incomingChanID: aliceLink.ShortChanID(),
incomingHTLCID: 0,
obfuscator: NewMockObfuscator(),
}
circuit = makePaymentCircuit(&htlc.PaymentHash, &addPkt)
_, err = coreLink.cfg.Switch.commitCircuits(&circuit)
if err != nil {
t.Fatalf("unable to commit circuit: %v", err)
}
addPkt.outgoingChanID = carolChanID
addPkt.outgoingHTLCID = 0
err = coreLink.cfg.Switch.openCircuits(addPkt.keystone())
if err != nil {
t.Fatalf("unable to set keystone: %v", err)
}
// Next, we'll settle the HTLC with our knowledge of the pre-image that
// we eventually learn (simulating a multi-hop payment). The bandwidth
// of the channel should now be re-balanced to the starting point.
settlePkt := htlcPacket{
incomingChanID: aliceLink.ShortChanID(),
incomingHTLCID: 0,
circuit: &circuit,
outgoingChanID: addPkt.outgoingChanID,
outgoingHTLCID: addPkt.outgoingHTLCID,
htlc: &lnwire.UpdateFulfillHTLC{
ID: bobIndex,
ID: 0,
PaymentPreimage: invoice.Terms.PaymentPreimage,
},
obfuscator: NewMockObfuscator(),
}
aliceLink.HandleSwitchPacket(&settlePkt)
if err := aliceLink.HandleSwitchPacket(&settlePkt); err != nil {
t.Fatalf("unable to handle switch packet: %v", err)
}
time.Sleep(time.Millisecond * 500)
// Settling this HTLC gives Alice all her original bandwidth back.
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth)
// Alice wil send the Settle to Bob.
select {
case msg = <-aliceMsgs:
case <-time.After(2 * time.Second):
t.Fatalf("did not receive message")
}
settleHtlc, ok := msg.(*lnwire.UpdateFulfillHTLC)
settleMsg, ok := msg.(*lnwire.UpdateFulfillHTLC)
if !ok {
t.Fatalf("expected UpdateFulfillHTLC, got %T", msg)
}
pre := settleHtlc.PaymentPreimage
idx := settleHtlc.ID
err = bobChannel.ReceiveHTLCSettle(pre, idx)
err = bobChannel.ReceiveHTLCSettle(settleMsg.PaymentPreimage, settleMsg.ID)
if err != nil {
t.Fatalf("unable to receive settle: %v", err)
t.Fatalf("failed receiving fail htlc: %v", err)
}
// After a settle the link should do a state transition automatically,
// so we don't have to trigger it.
if err := handleStateUpdate(aliceLink, bobChannel); err != nil {
// After failing an HTLC, the link will automatically trigger
// a state update.
if err := handleStateUpdate(coreLink, bobChannel); err != nil {
t.Fatalf("unable to update state: %v", err)
}
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth)
// Finally, we'll test the scenario of failing an HTLC received from the
// Finally, we'll test the scenario of failing an HTLC received by the
// remote node. This should result in no perceived bandwidth changes.
htlcAmt, totalTimelock, hops = generateHops(htlcAmt, testStartingHeight,
aliceLink)
coreLink)
blob, err = generateRoute(hops...)
if err != nil {
t.Fatalf("unable to gen route: %v", err)
@ -1922,7 +2007,8 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
if err != nil {
t.Fatalf("unable to create payment: %v", err)
}
if err := aliceLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice(*invoice); err != nil {
err = coreLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice(*invoice)
if err != nil {
t.Fatalf("unable to add invoice to registry: %v", err)
}
@ -1940,21 +2026,49 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
// No changes before the HTLC is locked in.
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth)
if err := updateState(tmr, aliceLink, bobChannel, false); err != nil {
if err := updateState(tmr, coreLink, bobChannel, false); err != nil {
t.Fatalf("unable to update state: %v", err)
}
// After lock-in, Alice will have to pay the htlc fee.
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcFee)
// Now fail this HTLC.
failPkt := htlcPacket{
incomingHTLCID: bobIndex,
htlc: &lnwire.UpdateFailHTLC{
ID: bobIndex,
},
addPkt = htlcPacket{
htlc: htlc,
incomingChanID: aliceLink.ShortChanID(),
incomingHTLCID: 1,
obfuscator: NewMockObfuscator(),
}
circuit = makePaymentCircuit(&htlc.PaymentHash, &addPkt)
_, err = coreLink.cfg.Switch.commitCircuits(&circuit)
if err != nil {
t.Fatalf("unable to commit circuit: %v", err)
}
addPkt.outgoingChanID = carolChanID
addPkt.outgoingHTLCID = 1
err = coreLink.cfg.Switch.openCircuits(addPkt.keystone())
if err != nil {
t.Fatalf("unable to set keystone: %v", err)
}
failPkt := htlcPacket{
incomingChanID: aliceLink.ShortChanID(),
incomingHTLCID: 1,
circuit: &circuit,
outgoingChanID: addPkt.outgoingChanID,
outgoingHTLCID: addPkt.outgoingHTLCID,
htlc: &lnwire.UpdateFailHTLC{
ID: 1,
},
obfuscator: NewMockObfuscator(),
}
if err := aliceLink.HandleSwitchPacket(&failPkt); err != nil {
t.Fatalf("unable to handle switch packet: %v", err)
}
aliceLink.HandleSwitchPacket(&failPkt)
time.Sleep(time.Millisecond * 500)
// Alice should get all her bandwidth back.
@ -1977,7 +2091,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
// After failing an HTLC, the link will automatically trigger
// a state update.
if err := handleStateUpdate(aliceLink, bobChannel); err != nil {
if err := handleStateUpdate(coreLink, bobChannel); err != nil {
t.Fatalf("unable to update state: %v", err)
}
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth)
@ -2015,20 +2129,27 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
}
feePerKw := feeRate.FeePerKWeight()
// The starting bandwidth of the channel should be exactly the amount
// that we created the channel between her and Bob.
expectedBandwidth := lnwire.NewMSatFromSatoshis(chanAmt - defaultCommitFee)
assertLinkBandwidth(t, aliceLink, expectedBandwidth)
addLinkHTLC := func(amt lnwire.MilliSatoshi) [32]byte {
var htlcID uint64
addLinkHTLC := func(id uint64, amt lnwire.MilliSatoshi) [32]byte {
invoice, htlc, err := generatePayment(amt, amt, 5, mockBlob)
if err != nil {
t.Fatalf("unable to create payment: %v", err)
}
aliceLink.HandleSwitchPacket(&htlcPacket{
htlc: htlc,
amount: amt,
})
addPkt := &htlcPacket{
htlc: htlc,
incomingHTLCID: id,
amount: amt,
obfuscator: NewMockObfuscator(),
}
circuit := makePaymentCircuit(&htlc.PaymentHash, addPkt)
_, err = coreLink.cfg.Switch.commitCircuits(&circuit)
if err != nil {
t.Fatalf("unable to commit circuit: %v", err)
}
addPkt.circuit = &circuit
aliceLink.HandleSwitchPacket(addPkt)
return invoice.Terms.PaymentPreimage
}
@ -2040,10 +2161,11 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
const numHTLCs = lnwallet.MaxHTLCNumber / 2
var preImages [][32]byte
for i := 0; i < numHTLCs; i++ {
preImage := addLinkHTLC(htlcAmt)
preImage := addLinkHTLC(htlcID, htlcAmt)
preImages = append(preImages, preImage)
totalHtlcAmt += htlcAmt
htlcID++
}
// The HTLCs should all be sent to the remote.
@ -2051,8 +2173,8 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
for i := 0; i < numHTLCs; i++ {
select {
case msg = <-aliceMsgs:
case <-time.After(2 * time.Second):
t.Fatalf("did not receive message")
case <-time.After(5 * time.Second):
t.Fatalf("did not receive message %d", i)
}
addHtlc, ok := msg.(*lnwire.UpdateAddHTLC)
@ -2078,7 +2200,7 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
htlcFee := lnwire.NewMSatFromSatoshis(
feePerKw.FeeForWeight(commitWeight),
)
expectedBandwidth = aliceStartingBandwidth - totalHtlcAmt - htlcFee
expectedBandwidth := aliceStartingBandwidth - totalHtlcAmt - htlcFee
expectedBandwidth += lnwire.NewMSatFromSatoshis(defaultCommitFee)
assertLinkBandwidth(t, aliceLink, expectedBandwidth)
@ -2094,10 +2216,11 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
// bandwidth accounting is done properly.
const numOverFlowHTLCs = 20
for i := 0; i < numOverFlowHTLCs; i++ {
preImage := addLinkHTLC(htlcAmt)
preImage := addLinkHTLC(htlcID, htlcAmt)
preImages = append(preImages, preImage)
totalHtlcAmt += htlcAmt
htlcID++
}
// No messages should be sent to the remote at this point.
@ -2245,10 +2368,18 @@ func TestChannelLinkBandwidthChanReserve(t *testing.T) {
if err != nil {
t.Fatalf("unable to create payment: %v", err)
}
addPkt := htlcPacket{
htlc: htlc,
addPkt := &htlcPacket{
htlc: htlc,
obfuscator: NewMockObfuscator(),
}
aliceLink.HandleSwitchPacket(&addPkt)
circuit := makePaymentCircuit(&htlc.PaymentHash, addPkt)
_, err = coreLink.cfg.Switch.commitCircuits(&circuit)
if err != nil {
t.Fatalf("unable to commit circuit: %v", err)
}
aliceLink.HandleSwitchPacket(addPkt)
time.Sleep(time.Millisecond * 100)
assertLinkBandwidth(t, aliceLink, aliceStartingBandwidth-htlcAmt-htlcFee)
@ -2834,11 +2965,11 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
}
}
// TestChannelLinkRejectDuplicatePayment tests that if a link receives an
// incoming HTLC for a payment we have already settled, then it rejects the
// HTLC. We do this as we want to enforce the fact that invoices are only to be
// used _once.
func TestChannelLinkRejectDuplicatePayment(t *testing.T) {
// TestChannelLinkAcceptDuplicatePayment tests that if a link receives an
// incoming HTLC for a payment we have already settled, then it accepts the
// HTLC. We do this to simplify the processing of settles after restarts or
// failures, reducing ambiguity when a batch is only partially processed.
func TestChannelLinkAcceptDuplicatePayment(t *testing.T) {
t.Parallel()
// First, we'll create our traditional three hop network. We'll only be
@ -2891,8 +3022,8 @@ func TestChannelLinkRejectDuplicatePayment(t *testing.T) {
// as it's a duplicate request.
_, err = n.aliceServer.htlcSwitch.SendHTLC(n.bobServer.PubKey(), htlc,
newMockDeobfuscator())
if err.Error() != lnwire.CodeUnknownPaymentHash.String() {
t.Fatal("error haven't been received")
if err != nil {
t.Fatalf("error shouldn't have been received got: %v", err)
}
}