mirror of
https://github.com/aljazceru/lspd.git
synced 2025-12-23 08:44:23 +01:00
run combined tests for LND and CLN
This commit is contained in:
4
go.mod
4
go.mod
@@ -4,7 +4,7 @@ go 1.19
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aws/aws-sdk-go v1.30.20
|
github.com/aws/aws-sdk-go v1.30.20
|
||||||
github.com/breez/lntest v0.0.3
|
github.com/breez/lntest v0.0.6
|
||||||
github.com/btcsuite/btcd v0.23.1
|
github.com/btcsuite/btcd v0.23.1
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.1
|
github.com/btcsuite/btcd/btcec/v2 v2.2.1
|
||||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
|
||||||
@@ -176,4 +176,4 @@ require (
|
|||||||
|
|
||||||
replace github.com/lightningnetwork/lnd v0.15.1-beta => github.com/breez/lnd v0.15.0-beta.rc6.0.20220831104847-00b86a81e57a
|
replace github.com/lightningnetwork/lnd v0.15.1-beta => github.com/breez/lnd v0.15.0-beta.rc6.0.20220831104847-00b86a81e57a
|
||||||
|
|
||||||
replace github.com/niftynei/glightning v0.8.2 => github.com/breez/glightning v0.0.0-20221124075140-383be4672b47
|
replace github.com/niftynei/glightning v0.8.2 => github.com/breez/glightning v0.0.0-20221201092709-02feadd1d0ad
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package itest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/breez/lntest"
|
"github.com/breez/lntest"
|
||||||
@@ -10,24 +9,18 @@ import (
|
|||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOpenZeroConfChannelOnReceive(t *testing.T) {
|
func testOpenZeroConfChannelOnReceive(h *lntest.TestHarness, lsp LspNode, miner *lntest.Miner, timeout time.Time) {
|
||||||
harness := lntest.NewTestHarness(t)
|
alice := lntest.NewCoreLightningNode(h, miner, "Alice", timeout)
|
||||||
defer harness.TearDown()
|
bob := NewZeroConfNode(h, miner, "Bob", timeout)
|
||||||
|
|
||||||
timeout := time.Now().Add(time.Minute)
|
|
||||||
|
|
||||||
miner := lntest.NewMiner(harness)
|
|
||||||
alice := lntest.NewCoreLightningNode(harness, miner, "Alice", timeout)
|
|
||||||
bob := NewZeroConfNode(harness, miner, "Bob", timeout)
|
|
||||||
lsp := NewLspdNode(harness, miner, "Lsp", timeout)
|
|
||||||
|
|
||||||
alice.Fund(10000000, timeout)
|
alice.Fund(10000000, timeout)
|
||||||
lsp.lightningNode.Fund(10000000, timeout)
|
lsp.LightningNode().Fund(10000000, timeout)
|
||||||
|
|
||||||
log.Print("Opening channel between Alice and the lsp")
|
log.Print("Opening channel between Alice and the lsp")
|
||||||
alice.OpenChannelAndWait(lsp.lightningNode, &lntest.OpenChannelOptions{
|
channel := alice.OpenChannel(lsp.LightningNode(), &lntest.OpenChannelOptions{
|
||||||
AmountSat: 1000000,
|
AmountSat: 1000000,
|
||||||
}, timeout)
|
})
|
||||||
|
alice.WaitForChannelReady(channel, timeout)
|
||||||
|
|
||||||
log.Printf("Adding bob's invoices")
|
log.Printf("Adding bob's invoices")
|
||||||
outerAmountMsat := uint64(2100000)
|
outerAmountMsat := uint64(2100000)
|
||||||
@@ -41,12 +34,12 @@ func TestOpenZeroConfChannelOnReceive(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
log.Print("Connecting bob to lspd")
|
log.Print("Connecting bob to lspd")
|
||||||
bob.lightningNode.ConnectPeer(lsp.lightningNode)
|
bob.lightningNode.ConnectPeer(lsp.LightningNode())
|
||||||
|
|
||||||
// NOTE: We pretend to be paying fees to the lsp, but actually we won't.
|
// NOTE: We pretend to be paying fees to the lsp, but actually we won't.
|
||||||
log.Printf("Registering payment with lsp")
|
log.Printf("Registering payment with lsp")
|
||||||
pretendAmount := outerAmountMsat - 2000000
|
pretendAmount := outerAmountMsat - 2000000
|
||||||
lsp.RegisterPayment(&lspd.PaymentInformation{
|
RegisterPayment(lsp, &lspd.PaymentInformation{
|
||||||
PaymentHash: innerInvoice.paymentHash,
|
PaymentHash: innerInvoice.paymentHash,
|
||||||
PaymentSecret: innerInvoice.paymentSecret,
|
PaymentSecret: innerInvoice.paymentSecret,
|
||||||
Destination: bob.lightningNode.NodeId(),
|
Destination: bob.lightningNode.NodeId(),
|
||||||
@@ -58,28 +51,22 @@ func TestOpenZeroConfChannelOnReceive(t *testing.T) {
|
|||||||
payResp := alice.Pay(outerInvoice.bolt11, timeout)
|
payResp := alice.Pay(outerInvoice.bolt11, timeout)
|
||||||
bobInvoice := bob.lightningNode.GetInvoice(payResp.PaymentHash)
|
bobInvoice := bob.lightningNode.GetInvoice(payResp.PaymentHash)
|
||||||
|
|
||||||
assert.DeepEqual(t, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
|
assert.DeepEqual(h.T, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
|
||||||
assert.Equal(t, outerAmountMsat, bobInvoice.AmountReceivedMsat)
|
assert.Equal(h.T, outerAmountMsat, bobInvoice.AmountReceivedMsat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenZeroConfSingleHtlc(t *testing.T) {
|
func testOpenZeroConfSingleHtlc(h *lntest.TestHarness, lsp LspNode, miner *lntest.Miner, timeout time.Time) {
|
||||||
harness := lntest.NewTestHarness(t)
|
alice := lntest.NewCoreLightningNode(h, miner, "Alice", timeout)
|
||||||
defer harness.TearDown()
|
bob := NewZeroConfNode(h, miner, "Bob", timeout)
|
||||||
|
|
||||||
timeout := time.Now().Add(time.Minute)
|
|
||||||
|
|
||||||
miner := lntest.NewMiner(harness)
|
|
||||||
alice := lntest.NewCoreLightningNode(harness, miner, "Alice", timeout)
|
|
||||||
bob := NewZeroConfNode(harness, miner, "Bob", timeout)
|
|
||||||
lsp := NewLspdNode(harness, miner, "Lsp", timeout)
|
|
||||||
|
|
||||||
alice.Fund(10000000, timeout)
|
alice.Fund(10000000, timeout)
|
||||||
lsp.lightningNode.Fund(10000000, timeout)
|
lsp.LightningNode().Fund(10000000, timeout)
|
||||||
|
|
||||||
log.Print("Opening channel between Alice and the lsp")
|
log.Print("Opening channel between Alice and the lsp")
|
||||||
channel := alice.OpenChannelAndWait(lsp.lightningNode, &lntest.OpenChannelOptions{
|
channel := alice.OpenChannel(lsp.LightningNode(), &lntest.OpenChannelOptions{
|
||||||
AmountSat: 1000000,
|
AmountSat: 1000000,
|
||||||
}, timeout)
|
})
|
||||||
|
channelId := alice.WaitForChannelReady(channel, timeout)
|
||||||
|
|
||||||
log.Printf("Adding bob's invoices")
|
log.Printf("Adding bob's invoices")
|
||||||
outerAmountMsat := uint64(2100000)
|
outerAmountMsat := uint64(2100000)
|
||||||
@@ -93,12 +80,12 @@ func TestOpenZeroConfSingleHtlc(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
log.Print("Connecting bob to lspd")
|
log.Print("Connecting bob to lspd")
|
||||||
bob.lightningNode.ConnectPeer(lsp.lightningNode)
|
bob.lightningNode.ConnectPeer(lsp.LightningNode())
|
||||||
|
|
||||||
// NOTE: We pretend to be paying fees to the lsp, but actually we won't.
|
// NOTE: We pretend to be paying fees to the lsp, but actually we won't.
|
||||||
log.Printf("Registering payment with lsp")
|
log.Printf("Registering payment with lsp")
|
||||||
pretendAmount := outerAmountMsat - 2000000
|
pretendAmount := outerAmountMsat - 2000000
|
||||||
lsp.RegisterPayment(&lspd.PaymentInformation{
|
RegisterPayment(lsp, &lspd.PaymentInformation{
|
||||||
PaymentHash: innerInvoice.paymentHash,
|
PaymentHash: innerInvoice.paymentHash,
|
||||||
PaymentSecret: innerInvoice.paymentSecret,
|
PaymentSecret: innerInvoice.paymentSecret,
|
||||||
Destination: bob.lightningNode.NodeId(),
|
Destination: bob.lightningNode.NodeId(),
|
||||||
@@ -107,23 +94,23 @@ func TestOpenZeroConfSingleHtlc(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
log.Printf("Alice paying")
|
log.Printf("Alice paying")
|
||||||
route := constructRoute(lsp.lightningNode, bob.lightningNode, channel.ChannelId, "1x0x0", outerAmountMsat)
|
route := constructRoute(lsp.LightningNode(), bob.lightningNode, channelId, lntest.NewShortChanIDFromString("1x0x0"), outerAmountMsat)
|
||||||
alice.StartPayPartViaRoute(outerAmountMsat, outerInvoice.paymentHash, outerInvoice.paymentSecret, 0, route)
|
payResp := alice.PayViaRoute(outerAmountMsat, outerInvoice.paymentHash, outerInvoice.paymentSecret, route, timeout)
|
||||||
payResp := alice.WaitForPaymentPart(outerInvoice.paymentHash, timeout, 0)
|
|
||||||
bobInvoice := bob.lightningNode.GetInvoice(payResp.PaymentHash)
|
bobInvoice := bob.lightningNode.GetInvoice(payResp.PaymentHash)
|
||||||
|
|
||||||
assert.DeepEqual(t, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
|
assert.DeepEqual(h.T, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
|
||||||
assert.Equal(t, outerAmountMsat, bobInvoice.AmountReceivedMsat)
|
assert.Equal(h.T, outerAmountMsat, bobInvoice.AmountReceivedMsat)
|
||||||
}
|
}
|
||||||
|
|
||||||
func constructRoute(
|
func constructRoute(
|
||||||
lsp *lntest.CoreLightningNode,
|
lsp lntest.LightningNode,
|
||||||
bob *lntest.CoreLightningNode,
|
bob lntest.LightningNode,
|
||||||
aliceLspChannel string,
|
aliceLspChannel lntest.ShortChannelID,
|
||||||
lspBobChannel string,
|
lspBobChannel lntest.ShortChannelID,
|
||||||
amountMsat uint64) *lntest.Route {
|
amountMsat uint64,
|
||||||
|
) *lntest.Route {
|
||||||
return &lntest.Route{
|
return &lntest.Route{
|
||||||
Route: []*lntest.Hop{
|
Hops: []*lntest.Hop{
|
||||||
{
|
{
|
||||||
Id: lsp.NodeId(),
|
Id: lsp.NodeId(),
|
||||||
Channel: aliceLspChannel,
|
Channel: aliceLspChannel,
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/breez/lntest"
|
"github.com/breez/lntest"
|
||||||
"github.com/breez/lspd/btceclegacy"
|
"github.com/breez/lspd/btceclegacy"
|
||||||
lspd "github.com/breez/lspd/rpc"
|
lspd "github.com/breez/lspd/rpc"
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
|
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
grpc "google.golang.org/grpc"
|
grpc "google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
@@ -35,28 +37,208 @@ var (
|
|||||||
lspCltvDelta uint16 = 40
|
lspCltvDelta uint16 = 40
|
||||||
)
|
)
|
||||||
|
|
||||||
type LspNode struct {
|
type LspNode interface {
|
||||||
|
Harness() *lntest.TestHarness
|
||||||
|
PublicKey() *btcec.PublicKey
|
||||||
|
Rpc() lspd.ChannelOpenerClient
|
||||||
|
NodeId() []byte
|
||||||
|
LightningNode() lntest.LightningNode
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClnLspNode struct {
|
||||||
harness *lntest.TestHarness
|
harness *lntest.TestHarness
|
||||||
lightningNode *lntest.CoreLightningNode
|
lightningNode *lntest.CoreLightningNode
|
||||||
rpc lspd.ChannelOpenerClient
|
rpc lspd.ChannelOpenerClient
|
||||||
rpcPort uint32
|
|
||||||
rpcHost string
|
|
||||||
privateKey btcec.PrivateKey
|
|
||||||
publicKey btcec.PublicKey
|
publicKey btcec.PublicKey
|
||||||
postgresBackend *PostgresContainer
|
postgresBackend *PostgresContainer
|
||||||
scriptDir string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string, timeout time.Time) *LspNode {
|
func (c *ClnLspNode) Harness() *lntest.TestHarness {
|
||||||
|
return c.harness
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClnLspNode) PublicKey() *btcec.PublicKey {
|
||||||
|
return &c.publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ClnLspNode) Rpc() lspd.ChannelOpenerClient {
|
||||||
|
return c.rpc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ClnLspNode) TearDown() error {
|
||||||
|
// NOTE: The lightningnode will be torn down on its own.
|
||||||
|
return l.postgresBackend.Shutdown(l.harness.Ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ClnLspNode) Cleanup() error {
|
||||||
|
return l.postgresBackend.Cleanup(l.harness.Ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ClnLspNode) NodeId() []byte {
|
||||||
|
return l.lightningNode.NodeId()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ClnLspNode) LightningNode() lntest.LightningNode {
|
||||||
|
return l.lightningNode
|
||||||
|
}
|
||||||
|
|
||||||
|
type LndLspNode struct {
|
||||||
|
harness *lntest.TestHarness
|
||||||
|
lightningNode *lntest.LndNode
|
||||||
|
rpc lspd.ChannelOpenerClient
|
||||||
|
publicKey btcec.PublicKey
|
||||||
|
postgresBackend *PostgresContainer
|
||||||
|
logFile *os.File
|
||||||
|
lspdCmd *exec.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LndLspNode) Harness() *lntest.TestHarness {
|
||||||
|
return c.harness
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LndLspNode) PublicKey() *btcec.PublicKey {
|
||||||
|
return &c.publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LndLspNode) Rpc() lspd.ChannelOpenerClient {
|
||||||
|
return c.rpc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LndLspNode) TearDown() error {
|
||||||
|
// NOTE: The lightningnode will be torn down on its own.
|
||||||
|
if l.lspdCmd != nil && l.lspdCmd.Process != nil {
|
||||||
|
err := l.lspdCmd.Process.Kill()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error stopping lspd process: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.logFile != nil {
|
||||||
|
err := l.logFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error closing logfile: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l.postgresBackend.Shutdown(l.harness.Ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LndLspNode) Cleanup() error {
|
||||||
|
return l.postgresBackend.Cleanup(l.harness.Ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LndLspNode) NodeId() []byte {
|
||||||
|
return l.lightningNode.NodeId()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LndLspNode) LightningNode() lntest.LightningNode {
|
||||||
|
return l.lightningNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClnLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string, timeout time.Time) LspNode {
|
||||||
|
scriptFilePath, grpcAddress, publ, postgresBackend := setupLspd(h, name, "RUN_CLN=true")
|
||||||
|
args := []string{
|
||||||
|
fmt.Sprintf("--plugin=%s", scriptFilePath),
|
||||||
|
fmt.Sprintf("--fee-base=%d", lspBaseFeeMsat),
|
||||||
|
fmt.Sprintf("--fee-per-satoshi=%d", lspFeeRatePpm),
|
||||||
|
fmt.Sprintf("--cltv-delta=%d", lspCltvDelta),
|
||||||
|
}
|
||||||
|
|
||||||
|
lightningNode := lntest.NewCoreLightningNode(h, m, name, timeout, args...)
|
||||||
|
|
||||||
|
conn, err := grpc.Dial(
|
||||||
|
grpcAddress,
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
|
grpc.WithPerRPCCredentials(&token{token: "hello"}),
|
||||||
|
)
|
||||||
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
|
client := lspd.NewChannelOpenerClient(conn)
|
||||||
|
|
||||||
|
lspNode := &ClnLspNode{
|
||||||
|
harness: h,
|
||||||
|
lightningNode: lightningNode,
|
||||||
|
rpc: client,
|
||||||
|
publicKey: *publ,
|
||||||
|
postgresBackend: postgresBackend,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.AddStoppable(lspNode)
|
||||||
|
h.AddCleanable(lspNode)
|
||||||
|
return lspNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLndLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string, timeout time.Time) LspNode {
|
||||||
|
args := []string{
|
||||||
|
"--protocol.zero-conf",
|
||||||
|
"--protocol.option-scid-alias",
|
||||||
|
"--requireinterceptor",
|
||||||
|
"--bitcoin.defaultchanconfs=0",
|
||||||
|
"--bitcoin.chanreservescript=\"0\"",
|
||||||
|
fmt.Sprintf("--bitcoin.basefee=%d", lspBaseFeeMsat),
|
||||||
|
fmt.Sprintf("--bitcoin.feerate=%d", lspFeeRatePpm),
|
||||||
|
fmt.Sprintf("--bitcoin.timelockdelta=%d", lspCltvDelta),
|
||||||
|
}
|
||||||
|
|
||||||
|
lightningNode := lntest.NewLndNode(h, m, name, timeout, args...)
|
||||||
|
tlsCert := strings.Replace(string(lightningNode.TlsCert()), "\n", "\\n", -1)
|
||||||
|
scriptFilePath, grpcAddress, publ, postgresBackend := setupLspd(h, name,
|
||||||
|
"RUN_LND=true",
|
||||||
|
fmt.Sprintf("LND_CERT=\"%s\"", tlsCert),
|
||||||
|
fmt.Sprintf("LND_ADDRESS=%s", lightningNode.GrpcHost()),
|
||||||
|
fmt.Sprintf("LND_MACAROON_HEX=%x", lightningNode.Macaroon()),
|
||||||
|
)
|
||||||
|
scriptDir := filepath.Dir(scriptFilePath)
|
||||||
|
logFilePath := filepath.Join(scriptDir, "lspd.log")
|
||||||
|
h.RegisterLogfile(logFilePath, fmt.Sprintf("lspd-%s", name))
|
||||||
|
|
||||||
|
lspdCmd := exec.CommandContext(h.Ctx, scriptFilePath)
|
||||||
|
logFile, err := os.Create(logFilePath)
|
||||||
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
|
lspdCmd.Stdout = logFile
|
||||||
|
lspdCmd.Stderr = logFile
|
||||||
|
|
||||||
|
log.Printf("%s: starting lspd %s", name, scriptFilePath)
|
||||||
|
err = lspdCmd.Start()
|
||||||
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
|
conn, err := grpc.Dial(
|
||||||
|
grpcAddress,
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
|
grpc.WithPerRPCCredentials(&token{token: "hello"}),
|
||||||
|
)
|
||||||
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
|
client := lspd.NewChannelOpenerClient(conn)
|
||||||
|
|
||||||
|
lspNode := &LndLspNode{
|
||||||
|
harness: h,
|
||||||
|
lightningNode: lightningNode,
|
||||||
|
rpc: client,
|
||||||
|
publicKey: *publ,
|
||||||
|
postgresBackend: postgresBackend,
|
||||||
|
logFile: logFile,
|
||||||
|
lspdCmd: lspdCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.AddStoppable(lspNode)
|
||||||
|
h.AddCleanable(lspNode)
|
||||||
|
return lspNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupLspd(h *lntest.TestHarness, name string, envExt ...string) (string, string, *secp256k1.PublicKey, *PostgresContainer) {
|
||||||
scriptDir := h.GetDirectory(fmt.Sprintf("lspd-%s", name))
|
scriptDir := h.GetDirectory(fmt.Sprintf("lspd-%s", name))
|
||||||
migrationsDir, err := GetMigrationsDir()
|
log.Printf("%s: Creating LSPD in dir %s", name, scriptDir)
|
||||||
|
migrationsDir, err := getMigrationsDir()
|
||||||
lntest.CheckError(h.T, err)
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
pgLogfile := filepath.Join(scriptDir, "postgres.log")
|
pgLogfile := filepath.Join(scriptDir, "postgres.log")
|
||||||
|
h.RegisterLogfile(pgLogfile, fmt.Sprintf("%s-postgres", name))
|
||||||
postgresBackend := StartPostgresContainer(h.T, h.Ctx, pgLogfile)
|
postgresBackend := StartPostgresContainer(h.T, h.Ctx, pgLogfile)
|
||||||
postgresBackend.RunMigrations(h.T, h.Ctx, migrationsDir)
|
postgresBackend.RunMigrations(h.T, h.Ctx, migrationsDir)
|
||||||
|
|
||||||
lspdBinary, err := GetLspdBinary()
|
lspdBinary, err := getLspdBinary()
|
||||||
lntest.CheckError(h.T, err)
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
lspdPort, err := lntest.GetPort()
|
lspdPort, err := lntest.GetPort()
|
||||||
@@ -65,23 +247,23 @@ func NewLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string, timeout ti
|
|||||||
lspdPrivateKeyBytes, err := GenerateRandomBytes(32)
|
lspdPrivateKeyBytes, err := GenerateRandomBytes(32)
|
||||||
lntest.CheckError(h.T, err)
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
priv, publ := btcec.PrivKeyFromBytes(lspdPrivateKeyBytes)
|
_, publ := btcec.PrivKeyFromBytes(lspdPrivateKeyBytes)
|
||||||
|
|
||||||
host := "localhost"
|
host := "localhost"
|
||||||
grpcAddress := fmt.Sprintf("%s:%d", host, lspdPort)
|
grpcAddress := fmt.Sprintf("%s:%d", host, lspdPort)
|
||||||
env := []string{
|
env := []string{
|
||||||
"NODE_NAME=lsp",
|
"NODE_NAME=lsp",
|
||||||
"NODE_PUBKEY=dunno",
|
"NODE_PUBKEY=dunno",
|
||||||
"NODE_HOST=host:port",
|
"NODE_HOST=host:port",
|
||||||
"RUN_CLN=true",
|
|
||||||
"TOKEN=hello",
|
"TOKEN=hello",
|
||||||
fmt.Sprintf("DATABASE_URL=%s", postgresBackend.ConnectionString()),
|
fmt.Sprintf("DATABASE_URL=%s", postgresBackend.ConnectionString()),
|
||||||
fmt.Sprintf("LISTEN_ADDRESS=%s", grpcAddress),
|
fmt.Sprintf("LISTEN_ADDRESS=%s", grpcAddress),
|
||||||
fmt.Sprintf("LSPD_PRIVATE_KEY=%x", lspdPrivateKeyBytes),
|
fmt.Sprintf("LSPD_PRIVATE_KEY=%x", lspdPrivateKeyBytes),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env = append(env, envExt...)
|
||||||
|
|
||||||
scriptFilePath := filepath.Join(scriptDir, "start-lspd.sh")
|
scriptFilePath := filepath.Join(scriptDir, "start-lspd.sh")
|
||||||
log.Printf("Creating lspd startup script at %s", scriptFilePath)
|
log.Printf("%s: Creating lspd startup script at %s", name, scriptFilePath)
|
||||||
scriptFile, err := os.OpenFile(scriptFilePath, os.O_CREATE|os.O_WRONLY, 0755)
|
scriptFile, err := os.OpenFile(scriptFilePath, os.O_CREATE|os.O_WRONLY, 0755)
|
||||||
lntest.CheckError(h.T, err)
|
lntest.CheckError(h.T, err)
|
||||||
|
|
||||||
@@ -101,73 +283,27 @@ func NewLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string, timeout ti
|
|||||||
lntest.CheckError(h.T, err)
|
lntest.CheckError(h.T, err)
|
||||||
scriptFile.Close()
|
scriptFile.Close()
|
||||||
|
|
||||||
args := []string{
|
return scriptFilePath, grpcAddress, publ, postgresBackend
|
||||||
fmt.Sprintf("--plugin=%s", scriptFilePath),
|
|
||||||
fmt.Sprintf("--fee-base=%d", lspBaseFeeMsat),
|
|
||||||
fmt.Sprintf("--fee-per-satoshi=%d", lspFeeRatePpm),
|
|
||||||
fmt.Sprintf("--cltv-delta=%d", lspCltvDelta),
|
|
||||||
}
|
|
||||||
|
|
||||||
lightningNode := lntest.NewCoreLightningNode(h, m, name, timeout, args...)
|
|
||||||
|
|
||||||
conn, err := grpc.Dial(
|
|
||||||
grpcAddress,
|
|
||||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
||||||
grpc.WithPerRPCCredentials(&token{token: "hello"}),
|
|
||||||
)
|
|
||||||
lntest.CheckError(h.T, err)
|
|
||||||
|
|
||||||
client := lspd.NewChannelOpenerClient(conn)
|
|
||||||
|
|
||||||
lspNode := &LspNode{
|
|
||||||
harness: h,
|
|
||||||
lightningNode: lightningNode,
|
|
||||||
rpc: client,
|
|
||||||
rpcPort: lspdPort,
|
|
||||||
rpcHost: host,
|
|
||||||
privateKey: *priv,
|
|
||||||
publicKey: *publ,
|
|
||||||
postgresBackend: postgresBackend,
|
|
||||||
scriptDir: scriptDir,
|
|
||||||
}
|
|
||||||
|
|
||||||
h.AddStoppable(lspNode)
|
|
||||||
h.AddCleanable(lspNode)
|
|
||||||
h.RegisterLogfile(pgLogfile, fmt.Sprintf("%s-postgres", name))
|
|
||||||
return lspNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LspNode) RegisterPayment(paymentInfo *lspd.PaymentInformation) {
|
func RegisterPayment(l LspNode, paymentInfo *lspd.PaymentInformation) {
|
||||||
serialized, err := proto.Marshal(paymentInfo)
|
serialized, err := proto.Marshal(paymentInfo)
|
||||||
lntest.CheckError(l.harness.T, err)
|
lntest.CheckError(l.Harness().T, err)
|
||||||
|
|
||||||
encrypted, err := btceclegacy.Encrypt(&l.publicKey, serialized)
|
encrypted, err := btceclegacy.Encrypt(l.PublicKey(), serialized)
|
||||||
lntest.CheckError(l.harness.T, err)
|
lntest.CheckError(l.Harness().T, err)
|
||||||
|
|
||||||
log.Printf("Registering payment")
|
log.Printf("Registering payment")
|
||||||
_, err = l.rpc.RegisterPayment(
|
_, err = l.Rpc().RegisterPayment(
|
||||||
l.harness.Ctx,
|
l.Harness().Ctx,
|
||||||
&lspd.RegisterPaymentRequest{
|
&lspd.RegisterPaymentRequest{
|
||||||
Blob: encrypted,
|
Blob: encrypted,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
lntest.CheckError(l.harness.T, err)
|
lntest.CheckError(l.Harness().T, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LspNode) TearDown() error {
|
func getLspdBinary() (string, error) {
|
||||||
// NOTE: The lightningnode will be torn down on its own.
|
|
||||||
return l.postgresBackend.Shutdown(l.harness.Ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *LspNode) Cleanup() error {
|
|
||||||
return l.postgresBackend.Cleanup(l.harness.Ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *LspNode) NodeId() []byte {
|
|
||||||
return l.lightningNode.NodeId()
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLspdBinary() (string, error) {
|
|
||||||
if lspdExecutable != nil {
|
if lspdExecutable != nil {
|
||||||
return *lspdExecutable, nil
|
return *lspdExecutable, nil
|
||||||
}
|
}
|
||||||
@@ -175,7 +311,7 @@ func GetLspdBinary() (string, error) {
|
|||||||
return exec.LookPath("lspd")
|
return exec.LookPath("lspd")
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMigrationsDir() (string, error) {
|
func getMigrationsDir() (string, error) {
|
||||||
if lspdMigrationsDir != nil {
|
if lspdMigrationsDir != nil {
|
||||||
return *lspdMigrationsDir, nil
|
return *lspdMigrationsDir, nil
|
||||||
}
|
}
|
||||||
|
|||||||
70
itest/lspd_test.go
Normal file
70
itest/lspd_test.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package itest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/breez/lntest"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultTimeout time.Duration = time.Second * 120
|
||||||
|
|
||||||
|
func TestLspd(t *testing.T) {
|
||||||
|
testCases := allTestCases
|
||||||
|
// runTests(t, testCases, "LND-lspd", func(h *lntest.TestHarness, m *lntest.Miner, t time.Time) LspNode {
|
||||||
|
// return NewLndLspdNode(h, m, "lsp", t)
|
||||||
|
// })
|
||||||
|
|
||||||
|
runTests(t, testCases, "CLN-lspd", func(h *lntest.TestHarness, m *lntest.Miner, t time.Time) LspNode {
|
||||||
|
return NewClnLspdNode(h, m, "lsp", t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTests(t *testing.T, testCases []*testCase, prefix string, lspFunc func(h *lntest.TestHarness, m *lntest.Miner, t time.Time) LspNode) {
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(fmt.Sprintf("%s: %s", prefix, testCase.name), func(t *testing.T) {
|
||||||
|
runTest(t, testCase, prefix, lspFunc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTest(t *testing.T, testCase *testCase, prefix string, lspFunc func(h *lntest.TestHarness, m *lntest.Miner, t time.Time) LspNode) {
|
||||||
|
log.Printf("%s: Running test case '%s'", prefix, testCase.name)
|
||||||
|
harness := lntest.NewTestHarness(t)
|
||||||
|
defer harness.TearDown()
|
||||||
|
|
||||||
|
var dd time.Duration
|
||||||
|
to := testCase.timeout
|
||||||
|
if to == dd {
|
||||||
|
to = defaultTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := time.Now().Add(to)
|
||||||
|
log.Printf("Using timeout %v", timeout.String())
|
||||||
|
log.Printf("Creating miner")
|
||||||
|
miner := lntest.NewMiner(harness)
|
||||||
|
log.Printf("Creating lsp")
|
||||||
|
lsp := lspFunc(harness, miner, timeout)
|
||||||
|
log.Printf("Run testcase")
|
||||||
|
testCase.test(harness, lsp, miner, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
name string
|
||||||
|
test func(h *lntest.TestHarness, lsp LspNode, miner *lntest.Miner, timeout time.Time)
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
var allTestCases = []*testCase{
|
||||||
|
{
|
||||||
|
name: "testOpenZeroConfChannelOnReceive",
|
||||||
|
test: testOpenZeroConfChannelOnReceive,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "testOpenZeroConfSingleHtlc",
|
||||||
|
test: testOpenZeroConfSingleHtlc,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -83,6 +83,13 @@ func StartPostgresContainer(t *testing.T, ctx context.Context, logfile string) *
|
|||||||
err = cli.ContainerStart(ctx, createResp.ID, types.ContainerStartOptions{})
|
err = cli.ContainerStart(ctx, createResp.ID, types.ContainerStartOptions{})
|
||||||
lntest.CheckError(t, err)
|
lntest.CheckError(t, err)
|
||||||
|
|
||||||
|
ct := &PostgresContainer{
|
||||||
|
id: createResp.ID,
|
||||||
|
password: "pgpassword",
|
||||||
|
port: port,
|
||||||
|
cli: cli,
|
||||||
|
}
|
||||||
|
|
||||||
HealthCheck:
|
HealthCheck:
|
||||||
for {
|
for {
|
||||||
inspect, err := cli.ContainerInspect(ctx, createResp.ID)
|
inspect, err := cli.ContainerInspect(ctx, createResp.ID)
|
||||||
@@ -93,17 +100,18 @@ HealthCheck:
|
|||||||
case "unhealthy":
|
case "unhealthy":
|
||||||
lntest.CheckError(t, errors.New("container unhealthy"))
|
lntest.CheckError(t, errors.New("container unhealthy"))
|
||||||
case "healthy":
|
case "healthy":
|
||||||
|
for {
|
||||||
|
pgxPool, err := pgxpool.Connect(context.Background(), ct.ConnectionString())
|
||||||
|
if err == nil {
|
||||||
|
pgxPool.Close()
|
||||||
break HealthCheck
|
break HealthCheck
|
||||||
default:
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ct := &PostgresContainer{
|
time.Sleep(50 * time.Millisecond)
|
||||||
id: createResp.ID,
|
}
|
||||||
password: "pgpassword",
|
default:
|
||||||
port: port,
|
time.Sleep(200 * time.Millisecond)
|
||||||
cli: cli,
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go ct.monitorLogs(logfile)
|
go ct.monitorLogs(logfile)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
@@ -108,7 +107,7 @@ type generateInvoicesRequest struct {
|
|||||||
innerAmountMsat uint64
|
innerAmountMsat uint64
|
||||||
outerAmountMsat uint64
|
outerAmountMsat uint64
|
||||||
description string
|
description string
|
||||||
lsp *LspNode
|
lsp LspNode
|
||||||
}
|
}
|
||||||
|
|
||||||
type invoice struct {
|
type invoice struct {
|
||||||
@@ -116,17 +115,15 @@ type invoice struct {
|
|||||||
paymentHash []byte
|
paymentHash []byte
|
||||||
paymentSecret []byte
|
paymentSecret []byte
|
||||||
paymentPreimage []byte
|
paymentPreimage []byte
|
||||||
expiresAt uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *ZeroConfNode) GenerateInvoices(req generateInvoicesRequest) (invoice, invoice) {
|
func (n *ZeroConfNode) GenerateInvoices(req generateInvoicesRequest) (invoice, invoice) {
|
||||||
preimage, err := GenerateRandomBytes(32)
|
preimage, err := GenerateRandomBytes(32)
|
||||||
lntest.CheckError(n.harness.T, err)
|
lntest.CheckError(n.harness.T, err)
|
||||||
|
|
||||||
lspNodeId, err := btcec.ParsePubKey(req.lsp.lightningNode.NodeId())
|
lspNodeId, err := btcec.ParsePubKey(req.lsp.NodeId())
|
||||||
lntest.CheckError(n.harness.T, err)
|
lntest.CheckError(n.harness.T, err)
|
||||||
|
|
||||||
log.Printf("Adding bob's invoices")
|
|
||||||
innerInvoice := n.lightningNode.CreateBolt11Invoice(&lntest.CreateInvoiceOptions{
|
innerInvoice := n.lightningNode.CreateBolt11Invoice(&lntest.CreateInvoiceOptions{
|
||||||
AmountMsat: req.innerAmountMsat,
|
AmountMsat: req.innerAmountMsat,
|
||||||
Description: &req.description,
|
Description: &req.description,
|
||||||
@@ -161,14 +158,12 @@ func (n *ZeroConfNode) GenerateInvoices(req generateInvoicesRequest) (invoice, i
|
|||||||
paymentHash: innerInvoice.PaymentHash,
|
paymentHash: innerInvoice.PaymentHash,
|
||||||
paymentSecret: innerInvoice.PaymentSecret,
|
paymentSecret: innerInvoice.PaymentSecret,
|
||||||
paymentPreimage: preimage,
|
paymentPreimage: preimage,
|
||||||
expiresAt: innerInvoice.ExpiresAt,
|
|
||||||
}
|
}
|
||||||
outer := invoice{
|
outer := invoice{
|
||||||
bolt11: outerInvoice,
|
bolt11: outerInvoice,
|
||||||
paymentHash: outerInvoiceRaw.PaymentHash[:],
|
paymentHash: outerInvoiceRaw.PaymentHash[:],
|
||||||
paymentSecret: innerInvoice.PaymentSecret,
|
paymentSecret: innerInvoice.PaymentSecret,
|
||||||
paymentPreimage: preimage,
|
paymentPreimage: preimage,
|
||||||
expiresAt: innerInvoice.ExpiresAt,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return inner, outer
|
return inner, outer
|
||||||
|
|||||||
Reference in New Issue
Block a user