2019-06-07 16:42:25 +02:00
|
|
|
package htlcswitch
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"math/rand"
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
2019-06-07 16:42:26 +02:00
|
|
|
"time"
|
2019-06-07 16:42:25 +02:00
|
|
|
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
2019-06-07 16:42:26 +02:00
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
2019-06-07 16:42:25 +02:00
|
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
2020-09-24 09:49:17 +02:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-06-07 16:42:25 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// TestNetworkResultSerialization checks that NetworkResults are properly
|
|
|
|
// (de)serialized.
|
|
|
|
func TestNetworkResultSerialization(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
var preimage lntypes.Preimage
|
|
|
|
if _, err := rand.Read(preimage[:]); err != nil {
|
|
|
|
t.Fatalf("unable gen rand preimag: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var chanID lnwire.ChannelID
|
|
|
|
if _, err := rand.Read(chanID[:]); err != nil {
|
|
|
|
t.Fatalf("unable gen rand chanid: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var reason [256]byte
|
|
|
|
if _, err := rand.Read(reason[:]); err != nil {
|
|
|
|
t.Fatalf("unable gen rand reason: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
settle := &lnwire.UpdateFulfillHTLC{
|
|
|
|
ChanID: chanID,
|
|
|
|
ID: 2,
|
|
|
|
PaymentPreimage: preimage,
|
2020-01-28 02:25:36 +01:00
|
|
|
ExtraData: make([]byte, 0),
|
2019-06-07 16:42:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fail := &lnwire.UpdateFailHTLC{
|
2020-01-28 02:25:36 +01:00
|
|
|
ChanID: chanID,
|
|
|
|
ID: 1,
|
|
|
|
Reason: []byte{},
|
|
|
|
ExtraData: make([]byte, 0),
|
2019-06-07 16:42:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fail2 := &lnwire.UpdateFailHTLC{
|
2020-01-28 02:25:36 +01:00
|
|
|
ChanID: chanID,
|
|
|
|
ID: 1,
|
|
|
|
Reason: reason[:],
|
|
|
|
ExtraData: make([]byte, 0),
|
2019-06-07 16:42:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
testCases := []*networkResult{
|
|
|
|
{
|
|
|
|
msg: settle,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
msg: fail,
|
|
|
|
unencrypted: false,
|
|
|
|
isResolution: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
msg: fail,
|
|
|
|
unencrypted: false,
|
|
|
|
isResolution: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
msg: fail2,
|
|
|
|
unencrypted: true,
|
|
|
|
isResolution: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, p := range testCases {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
if err := serializeNetworkResult(&buf, p); err != nil {
|
|
|
|
t.Fatalf("serialize failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
r := bytes.NewReader(buf.Bytes())
|
|
|
|
p1, err := deserializeNetworkResult(r)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to deserizlize: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(p, p1) {
|
|
|
|
t.Fatalf("not equal. %v vs %v", spew.Sdump(p),
|
|
|
|
spew.Sdump(p1))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-07 16:42:26 +02:00
|
|
|
|
|
|
|
// TestNetworkResultStore tests that the networkResult store behaves as
|
|
|
|
// expected, and that we can store, get and subscribe to results.
|
|
|
|
func TestNetworkResultStore(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const numResults = 4
|
|
|
|
|
2022-08-15 15:06:21 +02:00
|
|
|
db, err := channeldb.Open(t.TempDir())
|
2019-06-07 16:42:26 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2022-08-16 05:20:47 +02:00
|
|
|
t.Cleanup(func() { db.Close() })
|
2019-06-07 16:42:26 +02:00
|
|
|
|
|
|
|
store := newNetworkResultStore(db)
|
|
|
|
|
|
|
|
var results []*networkResult
|
|
|
|
for i := 0; i < numResults; i++ {
|
|
|
|
n := &networkResult{
|
|
|
|
msg: &lnwire.UpdateAddHTLC{},
|
|
|
|
unencrypted: true,
|
|
|
|
isResolution: true,
|
|
|
|
}
|
|
|
|
results = append(results, n)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Subscribe to 2 of them.
|
|
|
|
var subs []<-chan *networkResult
|
|
|
|
for i := uint64(0); i < 2; i++ {
|
|
|
|
sub, err := store.subscribeResult(i)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to subscribe: %v", err)
|
|
|
|
}
|
|
|
|
subs = append(subs, sub)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store three of them.
|
|
|
|
for i := uint64(0); i < 3; i++ {
|
|
|
|
err := store.storeResult(i, results[i])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to store result: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The two subscribers should be notified.
|
|
|
|
for _, sub := range subs {
|
|
|
|
select {
|
|
|
|
case <-sub:
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
t.Fatalf("no result received")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let the third one subscribe now. THe result should be received
|
|
|
|
// immediately.
|
|
|
|
sub, err := store.subscribeResult(2)
|
2022-05-05 22:11:50 +02:00
|
|
|
require.NoError(t, err, "unable to subscribe")
|
2019-06-07 16:42:26 +02:00
|
|
|
select {
|
|
|
|
case <-sub:
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
t.Fatalf("no result received")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try fetching the result directly for the non-stored one. This should
|
|
|
|
// fail.
|
|
|
|
_, err = store.getResult(3)
|
|
|
|
if err != ErrPaymentIDNotFound {
|
|
|
|
t.Fatalf("expected ErrPaymentIDNotFound, got %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the result and try again.
|
|
|
|
err = store.storeResult(3, results[3])
|
2022-05-05 22:11:50 +02:00
|
|
|
require.NoError(t, err, "unable to store result")
|
2019-06-07 16:42:26 +02:00
|
|
|
|
|
|
|
_, err = store.getResult(3)
|
2022-05-05 22:11:50 +02:00
|
|
|
require.NoError(t, err, "unable to get result")
|
2019-06-07 16:42:26 +02:00
|
|
|
|
|
|
|
// Since we don't delete results from the store (yet), make sure we
|
|
|
|
// will get subscriptions for all of them.
|
|
|
|
for i := uint64(0); i < numResults; i++ {
|
|
|
|
sub, err := store.subscribeResult(i)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to subscribe: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-sub:
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
t.Fatalf("no result received")
|
|
|
|
}
|
|
|
|
}
|
2020-09-24 09:49:17 +02:00
|
|
|
|
|
|
|
// Clean the store keeping the first two results.
|
|
|
|
toKeep := map[uint64]struct{}{
|
|
|
|
0: {},
|
|
|
|
1: {},
|
|
|
|
}
|
|
|
|
// Finally, delete the result.
|
|
|
|
err = store.cleanStore(toKeep)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Payment IDs 0 and 1 should be found, 2 and 3 should be deleted.
|
|
|
|
for i := uint64(0); i < numResults; i++ {
|
|
|
|
_, err = store.getResult(i)
|
|
|
|
if i <= 1 {
|
|
|
|
require.NoError(t, err, "unable to get result")
|
|
|
|
}
|
|
|
|
if i >= 2 && err != ErrPaymentIDNotFound {
|
|
|
|
t.Fatalf("expected ErrPaymentIDNotFound, got %v", err)
|
|
|
|
}
|
|
|
|
}
|
2019-06-07 16:42:26 +02:00
|
|
|
}
|