accounts: implement kvdb DebitAccount

This commit introduces the `DebitAccount` function in the kvdb store,
to support decreasing an existing off-chain account’s balance by a
specified amount in the database.
This commit is contained in:
Viktor Tigerström 2025-02-05 18:14:07 +01:00
parent cc003ab7a7
commit 3d67a7e7cb
No known key found for this signature in database
GPG key ID: B984570980684DCC
3 changed files with 60 additions and 0 deletions

View file

@ -230,6 +230,11 @@ type Store interface {
CreditAccount(ctx context.Context, id AccountID,
amount lnwire.MilliSatoshi) error
// DebitAccount decreases the balance of the account with the
// given ID by the given amount.
DebitAccount(ctx context.Context, id AccountID,
amount lnwire.MilliSatoshi) error
// UpsertAccountPayment updates or inserts a payment entry for the given
// account. Various functional options can be passed to modify the
// behavior of the method. The returned boolean is true if the payment

View file

@ -244,6 +244,33 @@ func (s *BoltStore) CreditAccount(_ context.Context, id AccountID,
return s.updateAccount(id, update)
}
// DebitAccount decreases the balance of the account with the given ID
// by the given amount.
//
// NOTE: This is part of the Store interface.
func (s *BoltStore) DebitAccount(_ context.Context, id AccountID,
amount lnwire.MilliSatoshi) error {
if amount > math.MaxInt64 {
return fmt.Errorf("amount %v exceeds the maximum of %v",
amount, int64(math.MaxInt64))
}
update := func(account *OffChainBalanceAccount) error {
if account.CurrentBalance-int64(amount) < 0 {
return fmt.Errorf("cannot debit %v from the account "+
"balance, as the resulting balance would be "+
"below 0", int64(amount/1000))
}
account.CurrentBalance -= int64(amount)
return nil
}
return s.updateAccount(id, update)
}
// UpsertAccountPayment updates or inserts a payment entry for the given
// account. Various functional options can be passed to modify the behavior of
// the method. The returned boolean is true if the payment was already known

View file

@ -2,6 +2,7 @@ package accounts
import (
"context"
"github.com/lightningnetwork/lnd/lnwire"
"testing"
"time"
@ -71,6 +72,14 @@ func TestAccountStore(t *testing.T) {
)
require.NoError(t, err)
// Adjust the account balance by first crediting 10000, and then
// debiting 5000.
err = store.CreditAccount(ctx, acct1.ID, lnwire.MilliSatoshi(10000))
require.NoError(t, err)
err = store.DebitAccount(ctx, acct1.ID, lnwire.MilliSatoshi(5000))
require.NoError(t, err)
// Update the in-memory account so that we can compare it with the
// account we get from the store.
acct1.CurrentBalance = -500
@ -85,11 +94,30 @@ func TestAccountStore(t *testing.T) {
}
acct1.Invoices[lntypes.Hash{12, 34, 56, 78}] = struct{}{}
acct1.Invoices[lntypes.Hash{34, 56, 78, 90}] = struct{}{}
acct1.CurrentBalance += 10000
acct1.CurrentBalance -= 5000
dbAccount, err = store.Account(ctx, acct1.ID)
require.NoError(t, err)
assertEqualAccounts(t, acct1, dbAccount)
// Test that adjusting the balance to exactly 0 should work, while
// adjusting the balance to below 0 should fail.
err = store.DebitAccount(
ctx, acct1.ID, lnwire.MilliSatoshi(acct1.CurrentBalance),
)
require.NoError(t, err)
acct1.CurrentBalance = 0
dbAccount, err = store.Account(ctx, acct1.ID)
require.NoError(t, err)
assertEqualAccounts(t, acct1, dbAccount)
// Adjusting the value to below 0 should fail.
err = store.DebitAccount(ctx, acct1.ID, lnwire.MilliSatoshi(1))
require.ErrorContains(t, err, "balance would be below 0")
// Sleep just a tiny bit to make sure we are never too quick to measure
// the expiry, even though the time is nanosecond scale and writing to
// the store and reading again should take at least a couple of