htlcswitch: add set of tests for the forwarding log
This commit is contained in:
parent
ad522a72c1
commit
473dfd115b
@ -683,6 +683,8 @@ out:
|
|||||||
// carried out by the remote peer. In the case of such an
|
// carried out by the remote peer. In the case of such an
|
||||||
// event, we'll wipe the channel state from the peer, and mark
|
// event, we'll wipe the channel state from the peer, and mark
|
||||||
// the contract as fully settled. Afterwards we can exit.
|
// the contract as fully settled. Afterwards we can exit.
|
||||||
|
//
|
||||||
|
// TODO(roasbeef): add force closure? also breach?
|
||||||
case <-l.cfg.ChainEvents.UnilateralClosure:
|
case <-l.cfg.ChainEvents.UnilateralClosure:
|
||||||
log.Warnf("Remote peer has closed ChannelPoint(%v) on-chain",
|
log.Warnf("Remote peer has closed ChannelPoint(%v) on-chain",
|
||||||
l.channel.ChannelPoint())
|
l.channel.ChannelPoint())
|
||||||
|
@ -82,6 +82,7 @@ var _ lnwallet.FeeEstimator = (*mockFeeEstimator)(nil)
|
|||||||
|
|
||||||
type mockForwardingLog struct {
|
type mockForwardingLog struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
||||||
events map[time.Time]channeldb.ForwardingEvent
|
events map[time.Time]channeldb.ForwardingEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +131,11 @@ func newMockServer(t testing.TB, name string) *mockServer {
|
|||||||
messages: make(chan lnwire.Message, 3000),
|
messages: make(chan lnwire.Message, 3000),
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
registry: newMockRegistry(),
|
registry: newMockRegistry(),
|
||||||
htlcSwitch: New(Config{}),
|
htlcSwitch: New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
}),
|
||||||
interceptorFuncs: make([]messageInterceptor, 0),
|
interceptorFuncs: make([]messageInterceptor, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -754,7 +754,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For local HTLC's we'll dispatch the settle event back to the
|
// For local HTLCs we'll dispatch the settle event back to the
|
||||||
// caller, rather than to the peer that sent us the HTLC
|
// caller, rather than to the peer that sent us the HTLC
|
||||||
// originally.
|
// originally.
|
||||||
localHTLC := packet.incomingChanID == (lnwire.ShortChannelID{})
|
localHTLC := packet.incomingChanID == (lnwire.ShortChannelID{})
|
||||||
|
@ -7,10 +7,13 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/btcsuite/fastsha256"
|
"github.com/btcsuite/fastsha256"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
"github.com/roasbeef/btcutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -35,7 +38,11 @@ func TestSwitchForward(t *testing.T) {
|
|||||||
alicePeer := newMockServer(t, "alice")
|
alicePeer := newMockServer(t, "alice")
|
||||||
bobPeer := newMockServer(t, "bob")
|
bobPeer := newMockServer(t, "bob")
|
||||||
|
|
||||||
s := New(Config{})
|
s := New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
})
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
@ -122,7 +129,11 @@ func TestSkipIneligibleLinksMultiHopForward(t *testing.T) {
|
|||||||
alicePeer := newMockServer(t, "alice")
|
alicePeer := newMockServer(t, "alice")
|
||||||
bobPeer := newMockServer(t, "bob")
|
bobPeer := newMockServer(t, "bob")
|
||||||
|
|
||||||
s := New(Config{})
|
s := New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
})
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
@ -177,7 +188,11 @@ func TestSkipIneligibleLinksLocalForward(t *testing.T) {
|
|||||||
// to forward form the get go.
|
// to forward form the get go.
|
||||||
alicePeer := newMockServer(t, "alice")
|
alicePeer := newMockServer(t, "alice")
|
||||||
|
|
||||||
s := New(Config{})
|
s := New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
})
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
@ -216,7 +231,11 @@ func TestSwitchCancel(t *testing.T) {
|
|||||||
alicePeer := newMockServer(t, "alice")
|
alicePeer := newMockServer(t, "alice")
|
||||||
bobPeer := newMockServer(t, "bob")
|
bobPeer := newMockServer(t, "bob")
|
||||||
|
|
||||||
s := New(Config{})
|
s := New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
})
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
@ -298,7 +317,11 @@ func TestSwitchAddSamePayment(t *testing.T) {
|
|||||||
alicePeer := newMockServer(t, "alice")
|
alicePeer := newMockServer(t, "alice")
|
||||||
bobPeer := newMockServer(t, "bob")
|
bobPeer := newMockServer(t, "bob")
|
||||||
|
|
||||||
s := New(Config{})
|
s := New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
})
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
@ -422,7 +445,11 @@ func TestSwitchSendPayment(t *testing.T) {
|
|||||||
|
|
||||||
alicePeer := newMockServer(t, "alice")
|
alicePeer := newMockServer(t, "alice")
|
||||||
|
|
||||||
s := New(Config{})
|
s := New(Config{
|
||||||
|
FwdingLog: &mockForwardingLog{
|
||||||
|
events: make(map[time.Time]channeldb.ForwardingEvent),
|
||||||
|
},
|
||||||
|
})
|
||||||
s.Start()
|
s.Start()
|
||||||
|
|
||||||
aliceChannelLink := newMockChannelLink(
|
aliceChannelLink := newMockChannelLink(
|
||||||
@ -542,3 +569,165 @@ func TestSwitchSendPayment(t *testing.T) {
|
|||||||
t.Fatal("wrong amount of pending payments")
|
t.Fatal("wrong amount of pending payments")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestLocalPaymentNoForwardingEvents tests that if we send a series of locally
|
||||||
|
// initiated payments, then they aren't reflected in the forwarding log.
|
||||||
|
func TestLocalPaymentNoForwardingEvents(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// First, we'll create our traditional three hop network. We'll only be
|
||||||
|
// interacting with and asserting the state of the first end point for
|
||||||
|
// this test.
|
||||||
|
channels, cleanUp, _, err := createClusterChannels(
|
||||||
|
btcutil.SatoshiPerBitcoin*3,
|
||||||
|
btcutil.SatoshiPerBitcoin*5)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create channel: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanUp()
|
||||||
|
|
||||||
|
n := newThreeHopNetwork(t, channels.aliceToBob, channels.bobToAlice,
|
||||||
|
channels.bobToCarol, channels.carolToBob, testStartingHeight)
|
||||||
|
if err := n.start(); err != nil {
|
||||||
|
t.Fatalf("unable to start three hop network: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll now craft and send a payment from Alice to Bob.
|
||||||
|
amount := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
||||||
|
htlcAmt, totalTimelock, hops := generateHops(
|
||||||
|
amount, testStartingHeight, n.firstBobChannelLink,
|
||||||
|
)
|
||||||
|
|
||||||
|
// With the payment crafted, we'll send it from Alice to Bob. We'll
|
||||||
|
// wait for Alice to receive the preimage for the payment before
|
||||||
|
// proceeding.
|
||||||
|
receiver := n.bobServer
|
||||||
|
_, err = n.makePayment(
|
||||||
|
n.aliceServer, receiver, n.bobServer.PubKey(), hops, amount,
|
||||||
|
htlcAmt, totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to make the payment: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, we'll forcibly stop the three hop network. Doing
|
||||||
|
// this will cause any pending forwarding events to be flushed by the
|
||||||
|
// various switches in the network.
|
||||||
|
n.stop()
|
||||||
|
|
||||||
|
// With all the switches stopped, we'll fetch Alice's mock forwarding
|
||||||
|
// event log.
|
||||||
|
log, ok := n.aliceServer.htlcSwitch.cfg.FwdingLog.(*mockForwardingLog)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("mockForwardingLog assertion failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we examine the memory of the forwarding log, then it should be
|
||||||
|
// blank.
|
||||||
|
if len(log.events) != 0 {
|
||||||
|
t.Fatalf("log should have no events, instead has: %v",
|
||||||
|
spew.Sdump(log.events))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestMultiHopPaymentForwardingEvents tests that if we send a series of
|
||||||
|
// multi-hop payments via Alice->Bob->Carol. Then Bob properly logs forwarding
|
||||||
|
// events, while Alice and Carol don't.
|
||||||
|
func TestMultiHopPaymentForwardingEvents(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// First, we'll create our traditional three hop network.
|
||||||
|
channels, cleanUp, _, err := createClusterChannels(
|
||||||
|
btcutil.SatoshiPerBitcoin*3,
|
||||||
|
btcutil.SatoshiPerBitcoin*5)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create channel: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanUp()
|
||||||
|
|
||||||
|
n := newThreeHopNetwork(t, channels.aliceToBob, channels.bobToAlice,
|
||||||
|
channels.bobToCarol, channels.carolToBob, testStartingHeight)
|
||||||
|
if err := n.start(); err != nil {
|
||||||
|
t.Fatalf("unable to start three hop network: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We'll make now 10 payments, of 100k satoshis each from Alice to
|
||||||
|
// Carol via Bob.
|
||||||
|
const numPayments = 10
|
||||||
|
finalAmt := lnwire.NewMSatFromSatoshis(100000)
|
||||||
|
htlcAmt, totalTimelock, hops := generateHops(
|
||||||
|
finalAmt, testStartingHeight, n.firstBobChannelLink,
|
||||||
|
n.carolChannelLink,
|
||||||
|
)
|
||||||
|
for i := 0; i < numPayments; i++ {
|
||||||
|
_, err := n.makePayment(
|
||||||
|
n.aliceServer, n.carolServer, n.bobServer.PubKey(),
|
||||||
|
hops, finalAmt, htlcAmt, totalTimelock,
|
||||||
|
).Wait(30 * time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to send payment: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * 200)
|
||||||
|
|
||||||
|
// With all 10 payments sent. We'll now manually stop each of the
|
||||||
|
// switches so we can examine their end state.
|
||||||
|
n.stop()
|
||||||
|
|
||||||
|
// Alice and Carol shouldn't have any recorded forwarding events, as
|
||||||
|
// they were the source and the sink for these payment flows.
|
||||||
|
aliceLog, ok := n.aliceServer.htlcSwitch.cfg.FwdingLog.(*mockForwardingLog)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("mockForwardingLog assertion failed")
|
||||||
|
}
|
||||||
|
if len(aliceLog.events) != 0 {
|
||||||
|
t.Fatalf("log should have no events, instead has: %v",
|
||||||
|
spew.Sdump(aliceLog.events))
|
||||||
|
}
|
||||||
|
carolLog, ok := n.carolServer.htlcSwitch.cfg.FwdingLog.(*mockForwardingLog)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("mockForwardingLog assertion failed")
|
||||||
|
}
|
||||||
|
if len(carolLog.events) != 0 {
|
||||||
|
t.Fatalf("log should have no events, instead has: %v",
|
||||||
|
spew.Sdump(carolLog.events))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bob on the other hand, should have 10 events.
|
||||||
|
bobLog, ok := n.bobServer.htlcSwitch.cfg.FwdingLog.(*mockForwardingLog)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("mockForwardingLog assertion failed")
|
||||||
|
}
|
||||||
|
if len(bobLog.events) != 10 {
|
||||||
|
t.Fatalf("log should have 10 events, instead has: %v",
|
||||||
|
spew.Sdump(bobLog.events))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each of the 10 events should have had all fields set properly.
|
||||||
|
for _, event := range bobLog.events {
|
||||||
|
// The incoming and outgoing channels should properly be set for
|
||||||
|
// the event.
|
||||||
|
if event.IncomingChanID != n.aliceChannelLink.ShortChanID() {
|
||||||
|
t.Fatalf("chan id mismatch: expected %v, got %v",
|
||||||
|
event.IncomingChanID,
|
||||||
|
n.aliceChannelLink.ShortChanID())
|
||||||
|
}
|
||||||
|
if event.OutgoingChanID != n.carolChannelLink.ShortChanID() {
|
||||||
|
t.Fatalf("chan id mismatch: expected %v, got %v",
|
||||||
|
event.OutgoingChanID,
|
||||||
|
n.carolChannelLink.ShortChanID())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additionally, the incoming and outgoing amounts should also
|
||||||
|
// be properly set.
|
||||||
|
if event.AmtIn != htlcAmt {
|
||||||
|
t.Fatalf("incoming amt mismatch: expected %v, got %v",
|
||||||
|
event.AmtIn, htlcAmt)
|
||||||
|
}
|
||||||
|
if event.AmtOut != finalAmt {
|
||||||
|
t.Fatalf("outgoing amt mismatch: expected %v, got %v",
|
||||||
|
event.AmtOut, finalAmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user