From 8da46e0b5aa08e724940e6565b5d3fe5d97b100e Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sun, 10 Dec 2017 16:19:40 -0800 Subject: [PATCH] htlcswitch: add tests to ensure we don't forward to inactive links --- htlcswitch/mock.go | 7 ++- htlcswitch/switch_test.go | 121 +++++++++++++++++++++++++++++++++++--- 2 files changed, 119 insertions(+), 9 deletions(-) diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 73e2c214..6581b97f 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -397,16 +397,19 @@ type mockChannelLink struct { peer Peer packets chan *htlcPacket + + eligible bool } func newMockChannelLink(chanID lnwire.ChannelID, shortChanID lnwire.ShortChannelID, - peer Peer) *mockChannelLink { + peer Peer, eligible bool) *mockChannelLink { return &mockChannelLink{ chanID: chanID, shortChanID: shortChanID, packets: make(chan *htlcPacket, 1), peer: peer, + eligible: eligible, } } @@ -430,7 +433,7 @@ func (f *mockChannelLink) Bandwidth() lnwire.MilliSatoshi { return 99999999 func (f *mockChannelLink) Peer() Peer { return f.peer } func (f *mockChannelLink) Start() error { return nil } func (f *mockChannelLink) Stop() {} -func (f *mockChannelLink) EligibleToForward() bool { return true } +func (f *mockChannelLink) EligibleToForward() bool { return f.eligible } var _ ChannelLink = (*mockChannelLink)(nil) diff --git a/htlcswitch/switch_test.go b/htlcswitch/switch_test.go index 11b39942..05cd6031 100644 --- a/htlcswitch/switch_test.go +++ b/htlcswitch/switch_test.go @@ -37,8 +37,12 @@ func TestSwitchForward(t *testing.T) { alicePeer := newMockServer(t, "alice") bobPeer := newMockServer(t, "bob") - aliceChannelLink := newMockChannelLink(chanID1, aliceChanID, alicePeer) - bobChannelLink := newMockChannelLink(chanID2, bobChanID, bobPeer) + aliceChannelLink := newMockChannelLink( + chanID1, aliceChanID, alicePeer, true, + ) + bobChannelLink := newMockChannelLink( + chanID2, bobChanID, bobPeer, true, + ) s := New(Config{}) s.Start() @@ -105,6 +109,99 @@ func TestSwitchForward(t *testing.T) { } } +// TestSkipIneligibleLinksMultiHopForward tests that if a multi-hop HTLC comes +// along, then we won't attempt to froward it down al ink that isn't yet able +// to forward any HTLC's. +func TestSkipIneligibleLinksMultiHopForward(t *testing.T) { + t.Parallel() + + var packet *htlcPacket + + alicePeer := newMockServer(t, "alice") + bobPeer := newMockServer(t, "bob") + + aliceChannelLink := newMockChannelLink( + chanID1, aliceChanID, alicePeer, true, + ) + + // We'll create a link for Bob, but mark the link as unable to forward + // any new outgoing HTLC's. + bobChannelLink := newMockChannelLink( + chanID2, bobChanID, bobPeer, false, + ) + + s := New(Config{}) + s.Start() + if err := s.AddLink(aliceChannelLink); err != nil { + t.Fatalf("unable to add alice link: %v", err) + } + if err := s.AddLink(bobChannelLink); err != nil { + t.Fatalf("unable to add bob link: %v", err) + } + + // Create a new packet that's destined for Bob as an incoming HTLC from + // Alice. + preimage := [sha256.Size]byte{1} + rhash := fastsha256.Sum256(preimage[:]) + packet = newAddPacket( + aliceChannelLink.ShortChanID(), + bobChannelLink.ShortChanID(), + &lnwire.UpdateAddHTLC{ + PaymentHash: rhash, + Amount: 1, + }, newMockObfuscator(), + ) + + // The request to forward should fail as + err := s.forward(packet) + if err == nil { + t.Fatalf("forwarding should have failed due to inactive link") + } + + if s.circuits.pending() != 0 { + t.Fatal("wrong amount of circuits") + } +} + +// TestSkipIneligibleLinksLocalForward ensures that the switch will not attempt +// to forward any HTLC's down a link that isn't yet eligible for forwarding. +func TestSkipIneligibleLinksLocalForward(t *testing.T) { + t.Parallel() + + // We'll create a single link for this test, marking it as being unable + // to forward form the get go. + alicePeer := newMockServer(t, "alice") + aliceChannelLink := newMockChannelLink( + chanID1, aliceChanID, alicePeer, false, + ) + + s := New(Config{}) + s.Start() + if err := s.AddLink(aliceChannelLink); err != nil { + t.Fatalf("unable to add alice link: %v", err) + } + + preimage := [sha256.Size]byte{1} + rhash := fastsha256.Sum256(preimage[:]) + addMsg := &lnwire.UpdateAddHTLC{ + PaymentHash: rhash, + Amount: 1, + } + + // We'll attempt to send out a new HTLC that has Alice as the first + // outgoing link. This should fail as Alice isn't yet able to forward + // any active HTLC's. + alicePub := aliceChannelLink.Peer().PubKey() + _, err := s.SendHTLC(alicePub, addMsg, nil) + if err == nil { + t.Fatalf("local forward should fail due to inactive link") + } + + if s.circuits.pending() != 0 { + t.Fatal("wrong amount of circuits") + } +} + // TestSwitchCancel checks that if htlc was rejected we remove unused // circuits. func TestSwitchCancel(t *testing.T) { @@ -115,8 +212,12 @@ func TestSwitchCancel(t *testing.T) { alicePeer := newMockServer(t, "alice") bobPeer := newMockServer(t, "bob") - aliceChannelLink := newMockChannelLink(chanID1, aliceChanID, alicePeer) - bobChannelLink := newMockChannelLink(chanID2, bobChanID, bobPeer) + aliceChannelLink := newMockChannelLink( + chanID1, aliceChanID, alicePeer, true, + ) + bobChannelLink := newMockChannelLink( + chanID2, bobChanID, bobPeer, true, + ) s := New(Config{}) s.Start() @@ -191,8 +292,12 @@ func TestSwitchAddSamePayment(t *testing.T) { alicePeer := newMockServer(t, "alice") bobPeer := newMockServer(t, "bob") - aliceChannelLink := newMockChannelLink(chanID1, aliceChanID, alicePeer) - bobChannelLink := newMockChannelLink(chanID2, bobChanID, bobPeer) + aliceChannelLink := newMockChannelLink( + chanID1, aliceChanID, alicePeer, true, + ) + bobChannelLink := newMockChannelLink( + chanID2, bobChanID, bobPeer, true, + ) s := New(Config{}) s.Start() @@ -288,7 +393,9 @@ func TestSwitchSendPayment(t *testing.T) { t.Parallel() alicePeer := newMockServer(t, "alice") - aliceChannelLink := newMockChannelLink(chanID1, aliceChanID, alicePeer) + aliceChannelLink := newMockChannelLink( + chanID1, aliceChanID, alicePeer, true, + ) s := New(Config{}) s.Start()