run combined tests for LND and CLN

This commit is contained in:
Jesse de Wit
2022-12-03 10:43:12 +01:00
parent d186e06323
commit b3c5b94531
6 changed files with 327 additions and 131 deletions

4
go.mod
View File

@@ -4,7 +4,7 @@ go 1.19
require (
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/btcec/v2 v2.2.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/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

View File

@@ -2,7 +2,6 @@ package itest
import (
"log"
"testing"
"time"
"github.com/breez/lntest"
@@ -10,24 +9,18 @@ import (
"gotest.tools/assert"
)
func TestOpenZeroConfChannelOnReceive(t *testing.T) {
harness := lntest.NewTestHarness(t)
defer harness.TearDown()
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)
func testOpenZeroConfChannelOnReceive(h *lntest.TestHarness, lsp LspNode, miner *lntest.Miner, timeout time.Time) {
alice := lntest.NewCoreLightningNode(h, miner, "Alice", timeout)
bob := NewZeroConfNode(h, miner, "Bob", timeout)
alice.Fund(10000000, timeout)
lsp.lightningNode.Fund(10000000, timeout)
lsp.LightningNode().Fund(10000000, timeout)
log.Print("Opening channel between Alice and the lsp")
alice.OpenChannelAndWait(lsp.lightningNode, &lntest.OpenChannelOptions{
channel := alice.OpenChannel(lsp.LightningNode(), &lntest.OpenChannelOptions{
AmountSat: 1000000,
}, timeout)
})
alice.WaitForChannelReady(channel, timeout)
log.Printf("Adding bob's invoices")
outerAmountMsat := uint64(2100000)
@@ -41,12 +34,12 @@ func TestOpenZeroConfChannelOnReceive(t *testing.T) {
})
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.
log.Printf("Registering payment with lsp")
pretendAmount := outerAmountMsat - 2000000
lsp.RegisterPayment(&lspd.PaymentInformation{
RegisterPayment(lsp, &lspd.PaymentInformation{
PaymentHash: innerInvoice.paymentHash,
PaymentSecret: innerInvoice.paymentSecret,
Destination: bob.lightningNode.NodeId(),
@@ -58,28 +51,22 @@ func TestOpenZeroConfChannelOnReceive(t *testing.T) {
payResp := alice.Pay(outerInvoice.bolt11, timeout)
bobInvoice := bob.lightningNode.GetInvoice(payResp.PaymentHash)
assert.DeepEqual(t, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
assert.Equal(t, outerAmountMsat, bobInvoice.AmountReceivedMsat)
assert.DeepEqual(h.T, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
assert.Equal(h.T, outerAmountMsat, bobInvoice.AmountReceivedMsat)
}
func TestOpenZeroConfSingleHtlc(t *testing.T) {
harness := lntest.NewTestHarness(t)
defer harness.TearDown()
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)
func testOpenZeroConfSingleHtlc(h *lntest.TestHarness, lsp LspNode, miner *lntest.Miner, timeout time.Time) {
alice := lntest.NewCoreLightningNode(h, miner, "Alice", timeout)
bob := NewZeroConfNode(h, miner, "Bob", timeout)
alice.Fund(10000000, timeout)
lsp.lightningNode.Fund(10000000, timeout)
lsp.LightningNode().Fund(10000000, timeout)
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,
}, timeout)
})
channelId := alice.WaitForChannelReady(channel, timeout)
log.Printf("Adding bob's invoices")
outerAmountMsat := uint64(2100000)
@@ -93,12 +80,12 @@ func TestOpenZeroConfSingleHtlc(t *testing.T) {
})
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.
log.Printf("Registering payment with lsp")
pretendAmount := outerAmountMsat - 2000000
lsp.RegisterPayment(&lspd.PaymentInformation{
RegisterPayment(lsp, &lspd.PaymentInformation{
PaymentHash: innerInvoice.paymentHash,
PaymentSecret: innerInvoice.paymentSecret,
Destination: bob.lightningNode.NodeId(),
@@ -107,23 +94,23 @@ func TestOpenZeroConfSingleHtlc(t *testing.T) {
})
log.Printf("Alice paying")
route := constructRoute(lsp.lightningNode, bob.lightningNode, channel.ChannelId, "1x0x0", outerAmountMsat)
alice.StartPayPartViaRoute(outerAmountMsat, outerInvoice.paymentHash, outerInvoice.paymentSecret, 0, route)
payResp := alice.WaitForPaymentPart(outerInvoice.paymentHash, timeout, 0)
route := constructRoute(lsp.LightningNode(), bob.lightningNode, channelId, lntest.NewShortChanIDFromString("1x0x0"), outerAmountMsat)
payResp := alice.PayViaRoute(outerAmountMsat, outerInvoice.paymentHash, outerInvoice.paymentSecret, route, timeout)
bobInvoice := bob.lightningNode.GetInvoice(payResp.PaymentHash)
assert.DeepEqual(t, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
assert.Equal(t, outerAmountMsat, bobInvoice.AmountReceivedMsat)
assert.DeepEqual(h.T, payResp.PaymentPreimage, bobInvoice.PaymentPreimage)
assert.Equal(h.T, outerAmountMsat, bobInvoice.AmountReceivedMsat)
}
func constructRoute(
lsp *lntest.CoreLightningNode,
bob *lntest.CoreLightningNode,
aliceLspChannel string,
lspBobChannel string,
amountMsat uint64) *lntest.Route {
lsp lntest.LightningNode,
bob lntest.LightningNode,
aliceLspChannel lntest.ShortChannelID,
lspBobChannel lntest.ShortChannelID,
amountMsat uint64,
) *lntest.Route {
return &lntest.Route{
Route: []*lntest.Hop{
Hops: []*lntest.Hop{
{
Id: lsp.NodeId(),
Channel: aliceLspChannel,

View File

@@ -9,12 +9,14 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/breez/lntest"
"github.com/breez/lspd/btceclegacy"
lspd "github.com/breez/lspd/rpc"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
@@ -35,28 +37,208 @@ var (
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
lightningNode *lntest.CoreLightningNode
rpc lspd.ChannelOpenerClient
rpcPort uint32
rpcHost string
privateKey btcec.PrivateKey
publicKey btcec.PublicKey
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))
migrationsDir, err := GetMigrationsDir()
log.Printf("%s: Creating LSPD in dir %s", name, scriptDir)
migrationsDir, err := getMigrationsDir()
lntest.CheckError(h.T, err)
pgLogfile := filepath.Join(scriptDir, "postgres.log")
h.RegisterLogfile(pgLogfile, fmt.Sprintf("%s-postgres", name))
postgresBackend := StartPostgresContainer(h.T, h.Ctx, pgLogfile)
postgresBackend.RunMigrations(h.T, h.Ctx, migrationsDir)
lspdBinary, err := GetLspdBinary()
lspdBinary, err := getLspdBinary()
lntest.CheckError(h.T, err)
lspdPort, err := lntest.GetPort()
@@ -65,23 +247,23 @@ func NewLspdNode(h *lntest.TestHarness, m *lntest.Miner, name string, timeout ti
lspdPrivateKeyBytes, err := GenerateRandomBytes(32)
lntest.CheckError(h.T, err)
priv, publ := btcec.PrivKeyFromBytes(lspdPrivateKeyBytes)
_, publ := btcec.PrivKeyFromBytes(lspdPrivateKeyBytes)
host := "localhost"
grpcAddress := fmt.Sprintf("%s:%d", host, lspdPort)
env := []string{
"NODE_NAME=lsp",
"NODE_PUBKEY=dunno",
"NODE_HOST=host:port",
"RUN_CLN=true",
"TOKEN=hello",
fmt.Sprintf("DATABASE_URL=%s", postgresBackend.ConnectionString()),
fmt.Sprintf("LISTEN_ADDRESS=%s", grpcAddress),
fmt.Sprintf("LSPD_PRIVATE_KEY=%x", lspdPrivateKeyBytes),
}
env = append(env, envExt...)
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)
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)
scriptFile.Close()
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 := &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
return scriptFilePath, grpcAddress, publ, postgresBackend
}
func (l *LspNode) RegisterPayment(paymentInfo *lspd.PaymentInformation) {
func RegisterPayment(l LspNode, paymentInfo *lspd.PaymentInformation) {
serialized, err := proto.Marshal(paymentInfo)
lntest.CheckError(l.harness.T, err)
lntest.CheckError(l.Harness().T, err)
encrypted, err := btceclegacy.Encrypt(&l.publicKey, serialized)
lntest.CheckError(l.harness.T, err)
encrypted, err := btceclegacy.Encrypt(l.PublicKey(), serialized)
lntest.CheckError(l.Harness().T, err)
log.Printf("Registering payment")
_, err = l.rpc.RegisterPayment(
l.harness.Ctx,
_, err = l.Rpc().RegisterPayment(
l.Harness().Ctx,
&lspd.RegisterPaymentRequest{
Blob: encrypted,
},
)
lntest.CheckError(l.harness.T, err)
lntest.CheckError(l.Harness().T, err)
}
func (l *LspNode) TearDown() 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) {
func getLspdBinary() (string, error) {
if lspdExecutable != nil {
return *lspdExecutable, nil
}
@@ -175,7 +311,7 @@ func GetLspdBinary() (string, error) {
return exec.LookPath("lspd")
}
func GetMigrationsDir() (string, error) {
func getMigrationsDir() (string, error) {
if lspdMigrationsDir != nil {
return *lspdMigrationsDir, nil
}

70
itest/lspd_test.go Normal file
View 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,
},
}

View File

@@ -83,6 +83,13 @@ func StartPostgresContainer(t *testing.T, ctx context.Context, logfile string) *
err = cli.ContainerStart(ctx, createResp.ID, types.ContainerStartOptions{})
lntest.CheckError(t, err)
ct := &PostgresContainer{
id: createResp.ID,
password: "pgpassword",
port: port,
cli: cli,
}
HealthCheck:
for {
inspect, err := cli.ContainerInspect(ctx, createResp.ID)
@@ -93,17 +100,18 @@ HealthCheck:
case "unhealthy":
lntest.CheckError(t, errors.New("container unhealthy"))
case "healthy":
for {
pgxPool, err := pgxpool.Connect(context.Background(), ct.ConnectionString())
if err == nil {
pgxPool.Close()
break HealthCheck
default:
time.Sleep(500 * time.Millisecond)
}
}
ct := &PostgresContainer{
id: createResp.ID,
password: "pgpassword",
port: port,
cli: cli,
time.Sleep(50 * time.Millisecond)
}
default:
time.Sleep(200 * time.Millisecond)
}
}
go ct.monitorLogs(logfile)

View File

@@ -4,7 +4,6 @@ import (
"bufio"
"crypto/sha256"
"fmt"
"log"
"os"
"path/filepath"
"time"
@@ -108,7 +107,7 @@ type generateInvoicesRequest struct {
innerAmountMsat uint64
outerAmountMsat uint64
description string
lsp *LspNode
lsp LspNode
}
type invoice struct {
@@ -116,17 +115,15 @@ type invoice struct {
paymentHash []byte
paymentSecret []byte
paymentPreimage []byte
expiresAt uint64
}
func (n *ZeroConfNode) GenerateInvoices(req generateInvoicesRequest) (invoice, invoice) {
preimage, err := GenerateRandomBytes(32)
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)
log.Printf("Adding bob's invoices")
innerInvoice := n.lightningNode.CreateBolt11Invoice(&lntest.CreateInvoiceOptions{
AmountMsat: req.innerAmountMsat,
Description: &req.description,
@@ -161,14 +158,12 @@ func (n *ZeroConfNode) GenerateInvoices(req generateInvoicesRequest) (invoice, i
paymentHash: innerInvoice.PaymentHash,
paymentSecret: innerInvoice.PaymentSecret,
paymentPreimage: preimage,
expiresAt: innerInvoice.ExpiresAt,
}
outer := invoice{
bolt11: outerInvoice,
paymentHash: outerInvoiceRaw.PaymentHash[:],
paymentSecret: innerInvoice.PaymentSecret,
paymentPreimage: preimage,
expiresAt: innerInvoice.ExpiresAt,
}
return inner, outer