diff --git a/itest/bob_offline_test.go b/itest/bob_offline_test.go index 45551cb..8b214b7 100644 --- a/itest/bob_offline_test.go +++ b/itest/bob_offline_test.go @@ -23,7 +23,7 @@ func testFailureBobOffline(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -44,7 +44,7 @@ func testFailureBobOffline(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // Kill the mobile client log.Printf("Stopping breez client") diff --git a/itest/cltv_test.go b/itest/cltv_test.go index 75a9f47..bbe0f5c 100644 --- a/itest/cltv_test.go +++ b/itest/cltv_test.go @@ -23,7 +23,7 @@ func testInvalidCltv(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -43,7 +43,7 @@ func testInvalidCltv(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) diff --git a/itest/dynamic_fee_test.go b/itest/dynamic_fee_test.go new file mode 100644 index 0000000..3763cfd --- /dev/null +++ b/itest/dynamic_fee_test.go @@ -0,0 +1,139 @@ +package itest + +import ( + "log" + "time" + + "github.com/breez/lntest" + lspd "github.com/breez/lspd/rpc" + "github.com/stretchr/testify/assert" +) + +func testDynamicFeeFlow(p *testParams) { + alice := lntest.NewClnNode(p.h, p.m, "Alice") + alice.Start() + alice.Fund(10000000) + p.lsp.LightningNode().Fund(10000000) + + log.Print("Opening channel between Alice and the lsp") + channel := alice.OpenChannel(p.lsp.LightningNode(), &lntest.OpenChannelOptions{ + AmountSat: publicChanAmount, + }) + channelId := alice.WaitForChannelReady(channel) + + log.Printf("Getting channel information") + p.Mempool().SetFees(&RecommendedFeesResponse{ + FastestFee: 3, + HalfHourFee: 3, + HourFee: 3, + EconomyFee: 3, + MinimumFee: 3, + }) + info := ChannelInformation(p.lsp) + assert.Len(p.t, info.OpeningFeeParamsMenu, 1) + params := info.OpeningFeeParamsMenu[0] + assert.Equal(p.t, uint64(3000000), params.MinMsat) + + log.Printf("Adding bob's invoices") + outerAmountMsat := uint64(4200000) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, params) + description := "Please pay me" + innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), + generateInvoicesRequest{ + innerAmountMsat: innerAmountMsat, + outerAmountMsat: outerAmountMsat, + description: description, + lsp: p.lsp, + }) + + p.BreezClient().SetHtlcAcceptor(innerAmountMsat) + log.Print("Connecting bob to lspd") + p.BreezClient().Node().ConnectPeer(p.lsp.LightningNode()) + + log.Printf("Testing some bad registrations") + err := RegisterPayment(p.lsp, &lspd.PaymentInformation{ + PaymentHash: innerInvoice.paymentHash, + PaymentSecret: innerInvoice.paymentSecret, + Destination: p.BreezClient().Node().NodeId(), + IncomingAmountMsat: int64(outerAmountMsat), + OutgoingAmountMsat: int64(innerAmountMsat), + OpeningFeeParams: &lspd.OpeningFeeParams{ + // modify minmsat + MinMsat: params.MinMsat + 1, + Proportional: params.Proportional, + ValidUntil: params.ValidUntil, + MaxIdleTime: params.MaxIdleTime, + MaxClientToSelfDelay: params.MaxClientToSelfDelay, + Promise: params.Promise, + }, + }, true) + assert.Contains(p.t, err.Error(), "invalid opening_fee_params") + + err = RegisterPayment(p.lsp, &lspd.PaymentInformation{ + PaymentHash: innerInvoice.paymentHash, + PaymentSecret: innerInvoice.paymentSecret, + Destination: p.BreezClient().Node().NodeId(), + IncomingAmountMsat: int64(outerAmountMsat), + OutgoingAmountMsat: int64(innerAmountMsat), + OpeningFeeParams: &lspd.OpeningFeeParams{ + MinMsat: params.MinMsat, + Proportional: params.Proportional, + ValidUntil: params.ValidUntil, + MaxIdleTime: params.MaxIdleTime, + MaxClientToSelfDelay: params.MaxClientToSelfDelay, + // Modify promise + Promise: params.Promise + "aa", + }, + }, true) + assert.Contains(p.t, err.Error(), "invalid opening_fee_params") + + err = RegisterPayment(p.lsp, &lspd.PaymentInformation{ + PaymentHash: innerInvoice.paymentHash, + PaymentSecret: innerInvoice.paymentSecret, + Destination: p.BreezClient().Node().NodeId(), + // Fee too low + IncomingAmountMsat: int64(2999999), + OutgoingAmountMsat: int64(0), + OpeningFeeParams: params, + }, true) + assert.Contains(p.t, err.Error(), "not enough fees") + + err = RegisterPayment(p.lsp, &lspd.PaymentInformation{ + PaymentHash: innerInvoice.paymentHash, + PaymentSecret: innerInvoice.paymentSecret, + Destination: p.BreezClient().Node().NodeId(), + IncomingAmountMsat: int64(outerAmountMsat), + OutgoingAmountMsat: int64(innerAmountMsat + 1), + OpeningFeeParams: params, + }, true) + assert.Contains(p.t, err.Error(), "not enough fees") + + // Now register the payment for real + log.Printf("Registering payment with lsp") + RegisterPayment(p.lsp, &lspd.PaymentInformation{ + PaymentHash: innerInvoice.paymentHash, + PaymentSecret: innerInvoice.paymentSecret, + Destination: p.BreezClient().Node().NodeId(), + IncomingAmountMsat: int64(outerAmountMsat), + OutgoingAmountMsat: int64(innerAmountMsat), + OpeningFeeParams: info.OpeningFeeParamsMenu[0], + }, false) + + // TODO: Fix race waiting for htlc interceptor. + log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) + <-time.After(htlcInterceptorDelay) + log.Printf("Alice paying") + route := constructRoute(p.lsp.LightningNode(), p.BreezClient().Node(), channelId, lntest.NewShortChanIDFromString("1x0x0"), outerAmountMsat) + payResp, err := alice.PayViaRoute(outerAmountMsat, outerInvoice.paymentHash, outerInvoice.paymentSecret, route) + lntest.CheckError(p.t, err) + bobInvoice := p.BreezClient().Node().GetInvoice(payResp.PaymentHash) + + assert.Equal(p.t, payResp.PaymentPreimage, bobInvoice.PaymentPreimage) + assert.Equal(p.t, innerAmountMsat, bobInvoice.AmountReceivedMsat) + + // Make sure capacity is correct + chans := p.BreezClient().Node().GetChannels() + assert.Equal(p.t, 1, len(chans)) + c := chans[0] + AssertChannelCapacity(p.t, outerAmountMsat, c.CapacityMsat) +} diff --git a/itest/intercept_zero_conf_test.go b/itest/intercept_zero_conf_test.go index 483840f..bc8b82d 100644 --- a/itest/intercept_zero_conf_test.go +++ b/itest/intercept_zero_conf_test.go @@ -25,7 +25,7 @@ func testOpenZeroConfChannelOnReceive(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -46,7 +46,7 @@ func testOpenZeroConfChannelOnReceive(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) @@ -79,7 +79,7 @@ func testOpenZeroConfSingleHtlc(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -100,7 +100,7 @@ func testOpenZeroConfSingleHtlc(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) diff --git a/itest/lspd_node.go b/itest/lspd_node.go index a4100c1..60834dd 100644 --- a/itest/lspd_node.go +++ b/itest/lspd_node.go @@ -223,7 +223,19 @@ func (l *lspBase) Initialize() error { return nil } -func RegisterPayment(l LspNode, paymentInfo *lspd.PaymentInformation) { +func ChannelInformation(l LspNode) *lspd.ChannelInformationReply { + info, err := l.Rpc().ChannelInformation( + l.Harness().Ctx, + &lspd.ChannelInformationRequest{}, + ) + if err != nil { + l.Harness().T.Fatalf("Failed to get ChannelInformation: %v", err) + } + + return info +} + +func RegisterPayment(l LspNode, paymentInfo *lspd.PaymentInformation, continueOnError bool) error { serialized, err := proto.Marshal(paymentInfo) lntest.CheckError(l.Harness().T, err) @@ -237,7 +249,12 @@ func RegisterPayment(l LspNode, paymentInfo *lspd.PaymentInformation) { Blob: encrypted, }, ) - lntest.CheckError(l.Harness().T, err) + + if !continueOnError { + lntest.CheckError(l.Harness().T, err) + } + + return err } func getLspdBinary() (string, error) { diff --git a/itest/lspd_test.go b/itest/lspd_test.go index e6dd3ff..4f403de 100644 --- a/itest/lspd_test.go +++ b/itest/lspd_test.go @@ -147,4 +147,8 @@ var allTestCases = []*testCase{ test: testOpenZeroConfUtxo, skipCreateLsp: true, }, + { + name: "testDynamicFeeFlow", + test: testDynamicFeeFlow, + }, } diff --git a/itest/no_balance_test.go b/itest/no_balance_test.go index 1c93c9d..498edd3 100644 --- a/itest/no_balance_test.go +++ b/itest/no_balance_test.go @@ -22,7 +22,7 @@ func testNoBalance(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -43,7 +43,7 @@ func testNoBalance(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) diff --git a/itest/probing_test.go b/itest/probing_test.go index 15a44b7..3352afe 100644 --- a/itest/probing_test.go +++ b/itest/probing_test.go @@ -24,7 +24,7 @@ func testProbing(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -45,7 +45,7 @@ func testProbing(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) diff --git a/itest/tag_test.go b/itest/tag_test.go index c671dc4..65af104 100644 --- a/itest/tag_test.go +++ b/itest/tag_test.go @@ -23,7 +23,7 @@ func registerPaymentWithTag(p *testParams) { IncomingAmountMsat: int64(25000000), OutgoingAmountMsat: int64(21000000), Tag: expected, - }) + }, false) pgxPool, err := pgxpool.Connect(p.h.Ctx, p.lsp.PostgresBackend().ConnectionString()) if err != nil { diff --git a/itest/test_common.go b/itest/test_common.go index 9d8f666..9a96ae9 100644 --- a/itest/test_common.go +++ b/itest/test_common.go @@ -2,8 +2,10 @@ package itest import ( "crypto/rand" + "log" "testing" + lspd "github.com/breez/lspd/rpc" "github.com/stretchr/testify/assert" ) @@ -26,15 +28,27 @@ func AssertChannelCapacity( assert.Equal(t, ((outerAmountMsat/1000)+100000)*1000, capacityMsat) } -func calculateInnerAmountMsat(lsp LspNode, outerAmountMsat uint64) uint64 { - fee := outerAmountMsat * 40 / 10_000 / 1_000 * 1_000 - if fee < 2000000 { - fee = 2000000 +func calculateInnerAmountMsat(lsp LspNode, outerAmountMsat uint64, params *lspd.OpeningFeeParams) uint64 { + var fee uint64 + log.Printf("%+v", params) + if params == nil { + fee = outerAmountMsat * 40 / 10_000 / 1_000 * 1_000 + if fee < 2000000 { + fee = 2000000 + } + } else { + fee = outerAmountMsat * 40 / 1_000_000 / 1_000 * 1_000 + if fee < params.MinMsat { + fee = params.MinMsat + } } - inner := outerAmountMsat - fee + if fee > outerAmountMsat { + lsp.Harness().Fatalf("Fee is higher than amount") + } - return inner + log.Printf("outer: %v, fee: %v", outerAmountMsat, fee) + return outerAmountMsat - fee } var publicChanAmount uint64 = 1000183 diff --git a/itest/zero_conf_utxo_test.go b/itest/zero_conf_utxo_test.go index 44ab3d1..30ea394 100644 --- a/itest/zero_conf_utxo_test.go +++ b/itest/zero_conf_utxo_test.go @@ -36,7 +36,7 @@ func testOpenZeroConfUtxo(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -57,7 +57,7 @@ func testOpenZeroConfUtxo(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay) diff --git a/itest/zero_reserve_test.go b/itest/zero_reserve_test.go index 6b1eab3..fad91b3 100644 --- a/itest/zero_reserve_test.go +++ b/itest/zero_reserve_test.go @@ -23,7 +23,7 @@ func testZeroReserve(p *testParams) { log.Printf("Adding bob's invoices") outerAmountMsat := uint64(2100000) - innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat) + innerAmountMsat := calculateInnerAmountMsat(p.lsp, outerAmountMsat, nil) description := "Please pay me" innerInvoice, outerInvoice := GenerateInvoices(p.BreezClient(), generateInvoicesRequest{ @@ -44,7 +44,7 @@ func testZeroReserve(p *testParams) { Destination: p.BreezClient().Node().NodeId(), IncomingAmountMsat: int64(outerAmountMsat), OutgoingAmountMsat: int64(innerAmountMsat), - }) + }, false) // TODO: Fix race waiting for htlc interceptor. log.Printf("Waiting %v to allow htlc interceptor to activate.", htlcInterceptorDelay)