Skip to content

Commit

Permalink
accounts: implement kvdb DebitAccount
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ViktorTigerstrom committed Feb 18, 2025
1 parent cc003ab commit 3d67a7e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
5 changes: 5 additions & 0 deletions accounts/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions accounts/store_kvdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions accounts/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package accounts

import (
"context"
"github.com/lightningnetwork/lnd/lnwire"
"testing"
"time"

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 3d67a7e

Please sign in to comment.