b86409cdb3
This commit gives the start for making the htlc manager and htlc switch testable. The testability of htlc switch have been achieved by mocking all external subsystems. The concrete list of updates: 1. create standalone package for htlc switch. 2. add "ChannelLink" interface, which represent the previous htlc link. 3. add "Peer" interface, which represent the remote node inside our subsystem. 4. add htlc switch config to htlc switch susbystem, which stores the handlers which are not elongs to any of the above interfaces. With this commit we are able test htlc switch even without having the concrete implementation of Peer, ChannelLink structures, they will be added later.
379 lines
9.5 KiB
Go
379 lines
9.5 KiB
Go
package htlcswitch
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/fastsha256"
|
|
"github.com/go-errors/errors"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
|
"github.com/roasbeef/btcd/wire"
|
|
)
|
|
|
|
var (
|
|
hash1, _ = chainhash.NewHash(bytes.Repeat([]byte("a"), 32))
|
|
hash2, _ = chainhash.NewHash(bytes.Repeat([]byte("b"), 32))
|
|
|
|
chanPoint1 = wire.NewOutPoint(hash1, 0)
|
|
chanPoint2 = wire.NewOutPoint(hash2, 0)
|
|
|
|
chanID1 = lnwire.NewChanIDFromOutPoint(chanPoint1)
|
|
chanID2 = lnwire.NewChanIDFromOutPoint(chanPoint2)
|
|
)
|
|
|
|
// TestSwitchForward checks the ability of htlc switch to forward add/settle
|
|
// requests.
|
|
func TestSwitchForward(t *testing.T) {
|
|
var packet *htlcPacket
|
|
|
|
alicePeer := newMockServer(t, "alice")
|
|
bobPeer := newMockServer(t, "bob")
|
|
|
|
aliceChannelLink := newMockChannelLink(chanID1, alicePeer)
|
|
bobChannelLink := newMockChannelLink(chanID2, bobPeer)
|
|
|
|
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 request which should be forwarder from alice channel
|
|
// link to bob channel link.
|
|
preimage := [sha256.Size]byte{1}
|
|
rhash := fastsha256.Sum256(preimage[:])
|
|
packet = newAddPacket(
|
|
aliceChannelLink.ChanID(),
|
|
NewHopID(bobChannelLink.Peer().PubKey()),
|
|
&lnwire.UpdateAddHTLC{
|
|
PaymentHash: rhash,
|
|
Amount: 1,
|
|
},
|
|
)
|
|
|
|
// Handle the request and checks that bob channel link received it.
|
|
if err := s.forward(packet); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-bobChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to destination")
|
|
}
|
|
|
|
if s.circuits.pending() != 1 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
|
|
// Create settle request pretending that bob link handled
|
|
// the add htlc request and sent the htlc settle request back. This
|
|
// request should be forwarder back to alice link.
|
|
packet = newSettlePacket(
|
|
bobChannelLink.ChanID(),
|
|
&lnwire.UpdateFufillHTLC{
|
|
PaymentPreimage: preimage,
|
|
},
|
|
rhash, 1)
|
|
|
|
// Handle the request and checks that payment circuit works properly.
|
|
if err := s.forward(packet); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-aliceChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to channelPoint")
|
|
}
|
|
|
|
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) {
|
|
var request *htlcPacket
|
|
|
|
alicePeer := newMockServer(t, "alice")
|
|
bobPeer := newMockServer(t, "bob")
|
|
|
|
aliceChannelLink := newMockChannelLink(chanID1, alicePeer)
|
|
bobChannelLink := newMockChannelLink(chanID2, bobPeer)
|
|
|
|
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 request which should be forwarder from alice channel link
|
|
// to bob channel link.
|
|
preimage := [sha256.Size]byte{1}
|
|
rhash := fastsha256.Sum256(preimage[:])
|
|
request = newAddPacket(
|
|
aliceChannelLink.ChanID(),
|
|
NewHopID(bobChannelLink.Peer().PubKey()),
|
|
&lnwire.UpdateAddHTLC{
|
|
PaymentHash: rhash,
|
|
Amount: 1,
|
|
},
|
|
)
|
|
|
|
// Handle the request and checks that bob channel link received it.
|
|
if err := s.forward(request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-bobChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to destination")
|
|
}
|
|
|
|
if s.circuits.pending() != 1 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
|
|
// Create settle request pretending that bob channel link handled
|
|
// the add htlc request and sent the htlc settle request back. This
|
|
// request should be forwarder back to alice channel link.
|
|
request = newFailPacket(
|
|
bobChannelLink.ChanID(),
|
|
&lnwire.UpdateFailHTLC{},
|
|
rhash, 1)
|
|
|
|
// Handle the request and checks that payment circuit works properly.
|
|
if err := s.forward(request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-aliceChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to channelPoint")
|
|
}
|
|
|
|
if s.circuits.pending() != 0 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
}
|
|
|
|
// TestSwitchAddSamePayment tests that we send the payment with the same
|
|
// payment hash.
|
|
func TestSwitchAddSamePayment(t *testing.T) {
|
|
var request *htlcPacket
|
|
|
|
alicePeer := newMockServer(t, "alice")
|
|
bobPeer := newMockServer(t, "bob")
|
|
|
|
aliceChannelLink := newMockChannelLink(chanID1, alicePeer)
|
|
bobChannelLink := newMockChannelLink(chanID2, bobPeer)
|
|
|
|
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 request which should be forwarder from alice channel link
|
|
// to bob channel link.
|
|
preimage := [sha256.Size]byte{1}
|
|
rhash := fastsha256.Sum256(preimage[:])
|
|
request = newAddPacket(
|
|
aliceChannelLink.ChanID(),
|
|
NewHopID(bobChannelLink.Peer().PubKey()),
|
|
&lnwire.UpdateAddHTLC{
|
|
PaymentHash: rhash,
|
|
Amount: 1,
|
|
},
|
|
)
|
|
|
|
// Handle the request and checks that bob channel link received it.
|
|
if err := s.forward(request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-bobChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to destination")
|
|
}
|
|
|
|
if s.circuits.pending() != 1 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
|
|
// Handle the request and checks that bob channel link received it.
|
|
if err := s.forward(request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if s.circuits.pending() != 2 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
|
|
// Create settle request pretending that bob channel link handled
|
|
// the add htlc request and sent the htlc settle request back. This
|
|
// request should be forwarder back to alice channel link.
|
|
request = newFailPacket(
|
|
bobChannelLink.ChanID(),
|
|
&lnwire.UpdateFailHTLC{},
|
|
rhash, 1)
|
|
|
|
// Handle the request and checks that payment circuit works properly.
|
|
if err := s.forward(request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-aliceChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to channelPoint")
|
|
}
|
|
|
|
if s.circuits.pending() != 1 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
|
|
// Handle the request and checks that payment circuit works properly.
|
|
if err := s.forward(request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-aliceChannelLink.packets:
|
|
break
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to channelPoint")
|
|
}
|
|
|
|
if s.circuits.pending() != 0 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
}
|
|
|
|
// TestSwitchSendPayment tests ability of htlc switch to respond to the
|
|
// users when response is came back from channel link.
|
|
func TestSwitchSendPayment(t *testing.T) {
|
|
alicePeer := newMockServer(t, "alice")
|
|
aliceChannelLink := newMockChannelLink(chanID1, alicePeer)
|
|
|
|
s := New(Config{})
|
|
s.Start()
|
|
if err := s.AddLink(aliceChannelLink); err != nil {
|
|
t.Fatalf("unable to add link: %v", err)
|
|
}
|
|
|
|
// Create request which should be forwarder from alice channel link
|
|
// to bob channel link.
|
|
preimage := [sha256.Size]byte{1}
|
|
rhash := fastsha256.Sum256(preimage[:])
|
|
update := &lnwire.UpdateAddHTLC{
|
|
PaymentHash: rhash,
|
|
Amount: 1,
|
|
}
|
|
|
|
// Handle the request and checks that bob channel link received it.
|
|
errChan := make(chan error)
|
|
go func() {
|
|
_, err := s.SendHTLC(aliceChannelLink.Peer().PubKey(), update)
|
|
errChan <- err
|
|
}()
|
|
|
|
go func() {
|
|
// Send the payment with the same payment hash and same
|
|
// amount and check that it will be propagated successfully
|
|
_, err := s.SendHTLC(aliceChannelLink.Peer().PubKey(), update)
|
|
errChan <- err
|
|
}()
|
|
|
|
select {
|
|
case <-aliceChannelLink.packets:
|
|
break
|
|
case err := <-errChan:
|
|
t.Fatalf("unable to send payment: %v", err)
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to destination")
|
|
}
|
|
|
|
select {
|
|
case <-aliceChannelLink.packets:
|
|
break
|
|
case err := <-errChan:
|
|
t.Fatalf("unable to send payment: %v", err)
|
|
case <-time.After(time.Second):
|
|
t.Fatal("request was not propogated to destination")
|
|
}
|
|
|
|
if s.numPendingPayments() != 2 {
|
|
t.Fatal("wrong amount of pending payments")
|
|
}
|
|
|
|
if s.circuits.pending() != 0 {
|
|
t.Fatal("wrong amount of circuits")
|
|
}
|
|
|
|
// Create fail request pretending that bob channel link handled
|
|
// the add htlc request with error and sent the htlc fail request
|
|
// back. This request should be forwarder back to alice channel link.
|
|
packet := newFailPacket(aliceChannelLink.ChanID(),
|
|
&lnwire.UpdateFailHTLC{
|
|
Reason: []byte{byte(lnwire.IncorrectValue)},
|
|
ID: 1,
|
|
},
|
|
rhash, 1)
|
|
|
|
if err := s.forward(packet); err != nil {
|
|
t.Fatalf("can't forward htlc packet: %v", err)
|
|
}
|
|
|
|
select {
|
|
case err := <-errChan:
|
|
if err.Error() != errors.New(lnwire.IncorrectValue).Error() {
|
|
t.Fatal("err wasn't received")
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("err wasn't received")
|
|
}
|
|
|
|
// Send second failure response and check that user were able to
|
|
// receive the error.
|
|
if err := s.forward(packet); err != nil {
|
|
t.Fatalf("can't forward htlc packet: %v", err)
|
|
}
|
|
|
|
select {
|
|
case err := <-errChan:
|
|
if err.Error() != errors.New(lnwire.IncorrectValue).Error() {
|
|
t.Fatal("err wasn't received")
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("err wasn't received")
|
|
}
|
|
|
|
if s.numPendingPayments() != 0 {
|
|
t.Fatal("wrong amount of pending payments")
|
|
}
|
|
}
|