Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/add fee provision 2 #395

Merged
merged 29 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
000177f
add db migration, add entry types
kiwiidb Jul 3, 2023
1313e08
add db migration
kiwiidb Jul 3, 2023
dc54877
fee reserves as seperate tx entries
kiwiidb Jul 4, 2023
3660db3
commit fee reserve tx entry
kiwiidb Jul 4, 2023
6b149af
fix cp error
kiwiidb Jul 4, 2023
f0237fa
update constraint
kiwiidb Jul 4, 2023
1c841b4
also get fee reserve tx by invoice id
kiwiidb Jul 4, 2023
4bd2613
fix bug
kiwiidb Jul 4, 2023
1677a97
remove debug
kiwiidb Jul 4, 2023
9ba016b
remove fee reserve id from tx entry
kiwiidb Jul 4, 2023
c20f02e
add trick to avoid looking up the fee account again
kiwiidb Jul 5, 2023
a22ab04
fix comment c/p
kiwiidb Jul 5, 2023
c3bd3bc
fix bugs
kiwiidb Jul 5, 2023
da3912f
wtf who wrote this
kiwiidb Jul 5, 2023
c0c2f3e
boy scouting
kiwiidb Jul 5, 2023
809a6f9
fix hodl invoice test
kiwiidb Jul 5, 2023
61132a7
no fee entry anymore for internal payments
kiwiidb Jul 5, 2023
ef2f267
fix internal payment test
kiwiidb Jul 5, 2023
ec0493c
fix async payment test
kiwiidb Jul 5, 2023
59ee273
fix async payment test
kiwiidb Jul 5, 2023
c09554a
fix async payment test
kiwiidb Jul 5, 2023
3527f44
fix async payment test
kiwiidb Jul 5, 2023
d8a9201
fix async payment test
kiwiidb Jul 5, 2023
9a6f9ab
add test to go below 0 with hodl invoices
kiwiidb Jul 5, 2023
3497d53
add test to show negative balances are no longer possible
kiwiidb Jul 5, 2023
8831541
fix comment
kiwiidb Jul 6, 2023
1f2ffb9
clean up tables after 2 tests
kiwiidb Jul 6, 2023
24428b3
add another user so they don't interfere
kiwiidb Jul 6, 2023
5a264de
fix migration issue
kiwiidb Jul 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions db/migrations/20230703120000_add_tx_entry_type.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alter table transaction_entries
add column entry_type character varying;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's with old payments? I guess we can update that entry for those?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they can just be kept as they are, it seems a lot of work and not very useful to update.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's inconsitent data that also requires special handling.
currently we only have incoming outgoing and fee transactions so the migration should be possible, e.g by iterating through the entries and checking the accounts.
I'd prefer not having old/inconsistent data if possible

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alter table transaction_entries drop constraint unique_tx_entry_tuple,
add constraint unique_tx_entry_tuple UNIQUE(user_id, invoice_id, debit_account_id, credit_account_id, entry_type);
11 changes: 11 additions & 0 deletions db/models/transactionentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import (
"time"
)

const (
EntryTypeIncoming = "incoming"
EntryTypeOutgoing = "outgoing"
EntryTypeFee = "fee"
EntryTypeFeeReserve = "fee_reserve"
EntryTypeFeeReserveReversal = "fee_reserve_reversal"
EntryTypeOutgoingReversal = "outgoing_reversal"
)

// TransactionEntry : Transaction Entries Model
type TransactionEntry struct {
ID int64 `bun:",pk,autoincrement"`
Expand All @@ -14,9 +23,11 @@ type TransactionEntry struct {
ParentID int64 `bun:",nullzero"`
Parent *TransactionEntry `bun:"rel:belongs-to"`
CreditAccountID int64 `bun:",notnull"`
FeeReserve *TransactionEntry `bun:"rel:belongs-to"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this reference work? where is the FeeReserveID saved?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's added there in https://github.com/getAlby/lndhub.go/blob/main/lib/service/checkpayments.go#L68.
The FeeReserveID is not saved on the transaction entry, I could not figure out how to get the id of the inserted record in https://github.com/getAlby/lndhub.go/blob/main/lib/service/invoices.go#L329 , I think because we're using a db transaction there it's not possible.

We're looking it up with its invoice id and entry_type = fee_reserve , and then adding it to its parent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so you say this feeReserveEntry here does not have an Id: https://github.com/getAlby/lndhub.go/blob/main/lib/service/invoices.go#L329C34-L329C49

which then can be used in here: https://github.com/getAlby/lndhub.go/blob/main/lib/service/invoices.go#L311-L316 (if moved down)

by SQL it should be possible
and for documentation and proper references I would find it nice to have it, then the other query is also easier because we simply get the association.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if bun does not do that automatically then I think we can use returning
https://bun.uptrace.dev/guide/query-insert.html#api

with that we at least should have the inserted ID in the result: https://pkg.go.dev/database/sql#Result
which we then can use to set the foreign key.

so we save the fee reserve, get the ID of that entry and save that in the tx and all this in a transaction.
PG can do that.

CreditAccount *Account `bun:"rel:belongs-to,join:credit_account_id=id"`
DebitAccountID int64 `bun:",notnull"`
DebitAccount *Account `bun:"rel:belongs-to,join:debit_account_id=id"`
Amount int64 `bun:",notnull"`
CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
EntryType string
}
135 changes: 116 additions & 19 deletions integration_tests/hodl_invoice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ type HodlInvoiceSuite struct {
service *service.LndhubService
userLogin ExpectedCreateUserResponseBody
userToken string
userToken2 string
invoiceUpdateSubCancelFn context.CancelFunc
hodlLND *LNDMockHodlWrapperAsync
}

func (suite *HodlInvoiceSuite) SetupSuite() {
mlnd := newDefaultMockLND()
externalLND, err := NewMockLND("1234567890abcdefabcd", 0, make(chan (*lnrpc.Invoice)))
externalLND, err := NewMockLND("1234567890abcdefabcd", 0, make(chan (*lnrpc.Invoice), 5))
if err != nil {
log.Fatalf("Error initializing test service: %v", err)
}
Expand All @@ -51,7 +52,7 @@ func (suite *HodlInvoiceSuite) SetupSuite() {
if err != nil {
log.Fatalf("Error initializing test service: %v", err)
}
users, userTokens, err := createUsers(svc, 1)
users, userTokens, err := createUsers(svc, 2)
if err != nil {
log.Fatalf("Error creating test users: %v", err)
}
Expand All @@ -66,21 +67,22 @@ func (suite *HodlInvoiceSuite) SetupSuite() {
e.HTTPErrorHandler = responses.HTTPErrorHandler
e.Validator = &lib.CustomValidator{Validator: validator.New()}
suite.echo = e
assert.Equal(suite.T(), 1, len(users))
assert.Equal(suite.T(), 1, len(userTokens))
assert.Equal(suite.T(), 2, len(users))
assert.Equal(suite.T(), 2, len(userTokens))
suite.userLogin = users[0]
suite.userToken = userTokens[0]
suite.userToken2 = userTokens[1]
suite.echo.Use(tokens.Middleware([]byte(suite.service.Config.JWTSecret)))
suite.echo.GET("/balance", controllers.NewBalanceController(suite.service).Balance)
suite.echo.POST("/addinvoice", controllers.NewAddInvoiceController(suite.service).AddInvoice)
suite.echo.POST("/payinvoice", controllers.NewPayInvoiceController(suite.service).PayInvoice)
}

func (suite *HodlInvoiceSuite) TestHodlInvoice() {
userFundingSats := 1000
externalSatRequested := 500
userFundingSats := int64(1000)
externalSatRequested := int64(500)
// fund user account
invoiceResponse := suite.createAddInvoiceReq(userFundingSats, "integration test external payment user", suite.userToken)
invoiceResponse := suite.createAddInvoiceReq(int(userFundingSats), "integration test external payment user", suite.userToken)
err := suite.mlnd.mockPaidInvoice(invoiceResponse, 0, false, nil)
assert.NoError(suite.T(), err)

Expand All @@ -90,7 +92,7 @@ func (suite *HodlInvoiceSuite) TestHodlInvoice() {
// create external invoice
externalInvoice := lnrpc.Invoice{
Memo: "integration tests: external pay from user",
Value: int64(externalSatRequested),
Value: externalSatRequested,
RPreimage: []byte("preimage1"),
}
invoice, err := suite.externalLND.AddInvoice(context.Background(), &externalInvoice)
Expand All @@ -107,7 +109,10 @@ func (suite *HodlInvoiceSuite) TestHodlInvoice() {
if err != nil {
fmt.Printf("Error when getting balance %v\n", err.Error())
}
assert.Equal(suite.T(), int64(userFundingSats-externalSatRequested), userBalance)

//also check that the fee reserve was reduced
feeReserve := suite.service.CalcFeeLimit(suite.externalLND.GetMainPubkey(), int64(externalSatRequested))
assert.Equal(suite.T(), userFundingSats-externalSatRequested-feeReserve, userBalance)

// check payment is pending
inv, err := suite.service.FindInvoiceByPaymentHash(context.Background(), userId, hex.EncodeToString(invoice.RHash))
Expand Down Expand Up @@ -153,16 +158,23 @@ func (suite *HodlInvoiceSuite) TestHodlInvoice() {
errorString := "FAILURE_REASON_INCORRECT_PAYMENT_DETAILS"
assert.Equal(suite.T(), errorString, invoices[0].ErrorMessage)

transactonEntries, err := suite.service.TransactionEntriesFor(context.Background(), userId)
transactionEntries, err := suite.service.TransactionEntriesFor(context.Background(), userId)
if err != nil {
fmt.Printf("Error when getting transaction entries %v\n", err.Error())
}
// check if there are 3 transaction entries, with reversed credit and debit account ids
assert.Equal(suite.T(), 3, len(transactonEntries))
assert.Equal(suite.T(), transactonEntries[1].CreditAccountID, transactonEntries[2].DebitAccountID)
assert.Equal(suite.T(), transactonEntries[1].DebitAccountID, transactonEntries[2].CreditAccountID)
assert.Equal(suite.T(), transactonEntries[1].Amount, int64(externalSatRequested))
assert.Equal(suite.T(), transactonEntries[2].Amount, int64(externalSatRequested))
// check if there are 5 transaction entries:
// - the incoming payment
// - the outgoing payment
// - the fee reserve + the fee reserve reversal
// - the outgoing payment reversal
// with reversed credit and debit account ids for payment 2/5 & payment 3/4
assert.Equal(suite.T(), 5, len(transactionEntries))
assert.Equal(suite.T(), transactionEntries[1].CreditAccountID, transactionEntries[4].DebitAccountID)
assert.Equal(suite.T(), transactionEntries[1].DebitAccountID, transactionEntries[4].CreditAccountID)
assert.Equal(suite.T(), transactionEntries[2].CreditAccountID, transactionEntries[3].DebitAccountID)
assert.Equal(suite.T(), transactionEntries[2].DebitAccountID, transactionEntries[3].CreditAccountID)
assert.Equal(suite.T(), transactionEntries[1].Amount, int64(externalSatRequested))
assert.Equal(suite.T(), transactionEntries[4].Amount, int64(externalSatRequested))

// create external invoice
externalInvoice = lnrpc.Invoice{
Expand Down Expand Up @@ -214,12 +226,97 @@ func (suite *HodlInvoiceSuite) TestHodlInvoice() {
inv, err = suite.service.FindInvoiceByPaymentHash(context.Background(), userId, hex.EncodeToString(invoice.RHash))
assert.NoError(suite.T(), err)
assert.Equal(suite.T(), common.InvoiceStateSettled, inv.State)
clearTable(suite.service, "invoices")
clearTable(suite.service, "transaction_entries")
clearTable(suite.service, "accounts")
}
func (suite *HodlInvoiceSuite) TestNegativeBalanceWithHodl() {
//10M funding, 5M sat requested
userFundingSats := 10000000
externalSatRequested := 5000000
userId := getUserIdFromToken(suite.userToken2)
// fund user account
invoiceResponse := suite.createAddInvoiceReq(userFundingSats, "integration test external payment user", suite.userToken2)
err := suite.mlnd.mockPaidInvoice(invoiceResponse, 0, false, nil)
assert.NoError(suite.T(), err)

// wait a bit for the callback event to hit
time.Sleep(10 * time.Millisecond)

// create external invoice
externalInvoice := lnrpc.Invoice{
Memo: "integration tests: external pay from user",
Value: int64(externalSatRequested),
RPreimage: []byte("preimage3"),
}
invoice, err := suite.externalLND.AddInvoice(context.Background(), &externalInvoice)
assert.NoError(suite.T(), err)
//the fee should be 1 %, so 50k sats (+1)
feeLimit := suite.service.CalcFeeLimit(suite.externalLND.GetMainPubkey(), int64(externalSatRequested))
// pay external from user, req will be canceled after 2 sec
go suite.createPayInvoiceReqWithCancel(invoice.PaymentRequest, suite.userToken2)
// wait for payment to be updated as pending in database
time.Sleep(3 * time.Second)
// check payment is pending
inv, err := suite.service.FindInvoiceByPaymentHash(context.Background(), userId, hex.EncodeToString(invoice.RHash))
assert.NoError(suite.T(), err)
assert.Equal(suite.T(), common.InvoiceStateInitialized, inv.State)

//drain balance from account: at this point we have 5 M, so we can pay 4.95M
drainInv := lnrpc.Invoice{
Memo: "integration tests: external pay from user",
Value: int64(4950000),
RPreimage: []byte("preimage4"),
}
drainInvoice, err := suite.externalLND.AddInvoice(context.Background(), &drainInv)
assert.NoError(suite.T(), err)
//pay drain invoice
go suite.createPayInvoiceReqWithCancel(drainInvoice.PaymentRequest, suite.userToken2)
time.Sleep(3 * time.Second)

//start payment checking loop
go func() {
err = suite.service.CheckAllPendingOutgoingPayments(context.Background())
assert.NoError(suite.T(), err)
}()
//wait a bit for routine to start
time.Sleep(time.Second)
//now settle both invoices with the maximum fee
suite.hodlLND.SettlePayment(lnrpc.Payment{
PaymentHash: hex.EncodeToString(drainInvoice.RHash),
Value: drainInv.Value,
CreationDate: 0,
FeeSat: feeLimit,
PaymentPreimage: "preimage3",
ValueSat: drainInv.Value,
ValueMsat: 0,
PaymentRequest: invoice.PaymentRequest,
Status: lnrpc.Payment_SUCCEEDED,
FailureReason: 0,
})
//wait a bit for db update to happen
time.Sleep(time.Second)
//send settle invoice with lnrpc.payment
suite.hodlLND.SettlePayment(lnrpc.Payment{
PaymentHash: hex.EncodeToString(invoice.RHash),
Value: externalInvoice.Value,
CreationDate: 0,
FeeSat: feeLimit,
PaymentPreimage: "preimage4",
ValueSat: externalInvoice.Value,
ValueMsat: 0,
PaymentRequest: invoice.PaymentRequest,
Status: lnrpc.Payment_SUCCEEDED,
FailureReason: 0,
})
//fetch user balance again
userBalance, err := suite.service.CurrentUserBalance(context.Background(), userId)
assert.NoError(suite.T(), err)
//assert the balance did not go below 0
assert.False(suite.T(), userBalance < 0)
}

func (suite *HodlInvoiceSuite) TearDownSuite() {
clearTable(suite.service, "invoices")
clearTable(suite.service, "transaction_entries")
clearTable(suite.service, "accounts")
suite.invoiceUpdateSubCancelFn()
}

Expand Down
29 changes: 13 additions & 16 deletions integration_tests/internal_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,11 @@ func (suite *PaymentTestSuite) TestInternalPayment() {
suite.echo.ServeHTTP(rec, req)
assert.Equal(suite.T(), http.StatusBadRequest, rec.Code)

transactonEntriesAlice, _ := suite.service.TransactionEntriesFor(context.Background(), aliceId)
transactionEntriesAlice, _ := suite.service.TransactionEntriesFor(context.Background(), aliceId)
aliceBalance, _ := suite.service.CurrentUserBalance(context.Background(), aliceId)
assert.Equal(suite.T(), 3, len(transactonEntriesAlice))
assert.Equal(suite.T(), int64(aliceFundingSats), transactonEntriesAlice[0].Amount)
assert.Equal(suite.T(), int64(bobSatRequested), transactonEntriesAlice[1].Amount)
assert.Equal(suite.T(), int64(fee), transactonEntriesAlice[2].Amount)
assert.Equal(suite.T(), transactonEntriesAlice[1].ID, transactonEntriesAlice[2].ParentID)
assert.Equal(suite.T(), 2, len(transactionEntriesAlice))
assert.Equal(suite.T(), int64(aliceFundingSats), transactionEntriesAlice[0].Amount)
assert.Equal(suite.T(), int64(bobSatRequested), transactionEntriesAlice[1].Amount)
assert.Equal(suite.T(), int64(aliceFundingSats-bobSatRequested-fee), aliceBalance)

bobBalance, _ := suite.service.CurrentUserBalance(context.Background(), bobId)
Expand Down Expand Up @@ -241,7 +239,7 @@ func (suite *PaymentTestSuite) TestInternalPaymentFail() {
assert.Equal(suite.T(), 2, len(invoices))
assert.Equal(suite.T(), common.InvoiceStateError, invoices[0].State)
assert.Equal(suite.T(), common.InvoiceStateSettled, invoices[1].State)
transactonEntries, err := suite.service.TransactionEntriesFor(context.Background(), userId)
transactionEntries, err := suite.service.TransactionEntriesFor(context.Background(), userId)
if err != nil {
fmt.Printf("Error when getting transaction entries %v\n", err.Error())
}
Expand All @@ -251,15 +249,14 @@ func (suite *PaymentTestSuite) TestInternalPaymentFail() {
fmt.Printf("Error when getting balance %v\n", err.Error())
}

// check if there are 5 transaction entries, with reversed credit and debit account ids for last 2
assert.Equal(suite.T(), 5, len(transactonEntries))
assert.Equal(suite.T(), int64(aliceFundingSats), transactonEntries[0].Amount)
assert.Equal(suite.T(), int64(bobSatRequested), transactonEntries[1].Amount)
assert.Equal(suite.T(), int64(fee), transactonEntries[2].Amount)
assert.Equal(suite.T(), transactonEntries[3].CreditAccountID, transactonEntries[4].DebitAccountID)
assert.Equal(suite.T(), transactonEntries[3].DebitAccountID, transactonEntries[4].CreditAccountID)
assert.Equal(suite.T(), transactonEntries[3].Amount, int64(bobSatRequested))
assert.Equal(suite.T(), transactonEntries[4].Amount, int64(bobSatRequested))
// check if there are 4 transaction entries, with reversed credit and debit account ids for last 2
assert.Equal(suite.T(), 4, len(transactionEntries))
assert.Equal(suite.T(), int64(aliceFundingSats), transactionEntries[0].Amount)
assert.Equal(suite.T(), int64(bobSatRequested), transactionEntries[1].Amount)
assert.Equal(suite.T(), transactionEntries[2].CreditAccountID, transactionEntries[3].DebitAccountID)
assert.Equal(suite.T(), transactionEntries[2].DebitAccountID, transactionEntries[3].CreditAccountID)
assert.Equal(suite.T(), transactionEntries[2].Amount, int64(bobSatRequested))
assert.Equal(suite.T(), transactionEntries[3].Amount, int64(bobSatRequested))
// assert that balance was reduced only once
assert.Equal(suite.T(), int64(aliceFundingSats)-int64(bobSatRequested+fee), int64(aliceBalance))
}
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/lnd_mock_hodl.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (hps *HodlPaymentSubscriber) Recv() (*lnrpc.Payment, error) {
func NewLNDMockHodlWrapperAsync(lnd lnd.LightningClientWrapper) (result *LNDMockHodlWrapperAsync, err error) {
return &LNDMockHodlWrapperAsync{
hps: &HodlPaymentSubscriber{
ch: make(chan lnrpc.Payment),
ch: make(chan lnrpc.Payment, 5),
},
LightningClientWrapper: lnd,
}, nil
Expand Down
40 changes: 20 additions & 20 deletions integration_tests/outgoing_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (suite *PaymentTestSuite) TestOutGoingPayment() {
assert.Equal(suite.T(), 1, len(outgoingInvoices))
assert.Equal(suite.T(), 1, len(incomingInvoices))

assert.Equal(suite.T(), 3, len(transactonEntries))
assert.Equal(suite.T(), 5, len(transactonEntries))

assert.Equal(suite.T(), int64(aliceFundingSats), transactonEntries[0].Amount)
assert.Equal(suite.T(), currentAccount.ID, transactonEntries[0].CreditAccountID)
Expand All @@ -77,13 +77,13 @@ func (suite *PaymentTestSuite) TestOutGoingPayment() {
assert.Equal(suite.T(), int64(0), transactonEntries[1].ParentID)
assert.Equal(suite.T(), outgoingInvoices[0].ID, transactonEntries[1].InvoiceID)

assert.Equal(suite.T(), int64(suite.mlnd.fee), transactonEntries[2].Amount)
assert.Equal(suite.T(), int64(suite.mlnd.fee), transactonEntries[4].Amount)
assert.Equal(suite.T(), feeAccount.ID, transactonEntries[2].CreditAccountID)
assert.Equal(suite.T(), currentAccount.ID, transactonEntries[2].DebitAccountID)
assert.Equal(suite.T(), outgoingInvoices[0].ID, transactonEntries[2].InvoiceID)

// make sure fee entry parent id is previous entry
assert.Equal(suite.T(), transactonEntries[1].ID, transactonEntries[2].ParentID)
assert.Equal(suite.T(), transactonEntries[1].ID, transactonEntries[4].ParentID)

//fetch transactions, make sure the fee is there
// check invoices again
Expand Down Expand Up @@ -134,7 +134,7 @@ func (suite *PaymentTestSuite) TestOutGoingPaymentWithNegativeBalance() {
assert.Equal(suite.T(), int64(-1), aliceBalance)

// check that no additional transaction entry was created
transactonEntries, err := suite.service.TransactionEntriesFor(context.Background(), userId)
transactionEntries, err := suite.service.TransactionEntriesFor(context.Background(), userId)
if err != nil {
fmt.Printf("Error when getting transaction entries %v\n", err.Error())
}
Expand All @@ -149,27 +149,27 @@ func (suite *PaymentTestSuite) TestOutGoingPaymentWithNegativeBalance() {
assert.Equal(suite.T(), 1, len(outgoingInvoices))
assert.Equal(suite.T(), 1, len(incomingInvoices))

assert.Equal(suite.T(), 3, len(transactonEntries))
assert.Equal(suite.T(), 5, len(transactionEntries))

assert.Equal(suite.T(), int64(aliceFundingSats), transactonEntries[0].Amount)
assert.Equal(suite.T(), currentAccount.ID, transactonEntries[0].CreditAccountID)
assert.Equal(suite.T(), incomingAccount.ID, transactonEntries[0].DebitAccountID)
assert.Equal(suite.T(), int64(0), transactonEntries[0].ParentID)
assert.Equal(suite.T(), incomingInvoices[0].ID, transactonEntries[0].InvoiceID)
assert.Equal(suite.T(), int64(aliceFundingSats), transactionEntries[0].Amount)
assert.Equal(suite.T(), currentAccount.ID, transactionEntries[0].CreditAccountID)
assert.Equal(suite.T(), incomingAccount.ID, transactionEntries[0].DebitAccountID)
assert.Equal(suite.T(), int64(0), transactionEntries[0].ParentID)
assert.Equal(suite.T(), incomingInvoices[0].ID, transactionEntries[0].InvoiceID)

assert.Equal(suite.T(), int64(externalSatRequested), transactonEntries[1].Amount)
assert.Equal(suite.T(), outgoingAccount.ID, transactonEntries[1].CreditAccountID)
assert.Equal(suite.T(), currentAccount.ID, transactonEntries[1].DebitAccountID)
assert.Equal(suite.T(), int64(0), transactonEntries[1].ParentID)
assert.Equal(suite.T(), outgoingInvoices[0].ID, transactonEntries[1].InvoiceID)
assert.Equal(suite.T(), int64(externalSatRequested), transactionEntries[1].Amount)
assert.Equal(suite.T(), outgoingAccount.ID, transactionEntries[1].CreditAccountID)
assert.Equal(suite.T(), currentAccount.ID, transactionEntries[1].DebitAccountID)
assert.Equal(suite.T(), int64(0), transactionEntries[1].ParentID)
assert.Equal(suite.T(), outgoingInvoices[0].ID, transactionEntries[1].InvoiceID)

assert.Equal(suite.T(), int64(suite.mlnd.fee), transactonEntries[2].Amount)
assert.Equal(suite.T(), feeAccount.ID, transactonEntries[2].CreditAccountID)
assert.Equal(suite.T(), currentAccount.ID, transactonEntries[2].DebitAccountID)
assert.Equal(suite.T(), outgoingInvoices[0].ID, transactonEntries[2].InvoiceID)
assert.Equal(suite.T(), int64(suite.mlnd.fee), transactionEntries[4].Amount)
assert.Equal(suite.T(), feeAccount.ID, transactionEntries[2].CreditAccountID)
assert.Equal(suite.T(), currentAccount.ID, transactionEntries[2].DebitAccountID)
assert.Equal(suite.T(), outgoingInvoices[0].ID, transactionEntries[2].InvoiceID)

// make sure fee entry parent id is previous entry
assert.Equal(suite.T(), transactonEntries[1].ID, transactonEntries[2].ParentID)
assert.Equal(suite.T(), transactionEntries[1].ID, transactionEntries[4].ParentID)
}

func (suite *PaymentTestSuite) TestZeroAmountInvoice() {
Expand Down
Loading