Skip to content

Commit edaf59d

Browse files
authored
Merge pull request #938 from ellemouton/sql2Accounts2
[sql-2] accounts: start replacing calls to UpdateAccount
2 parents 211865a + 34d1f67 commit edaf59d

File tree

5 files changed

+294
-29
lines changed

5 files changed

+294
-29
lines changed

accounts/interface.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"time"
99

10+
"github.com/lightningnetwork/lnd/fn"
1011
"github.com/lightningnetwork/lnd/lnrpc"
1112
"github.com/lightningnetwork/lnd/lntypes"
1213
"github.com/lightningnetwork/lnd/lnwire"
@@ -219,6 +220,21 @@ type Store interface {
219220
// Accounts retrieves all accounts from the store and un-marshals them.
220221
Accounts(ctx context.Context) ([]*OffChainBalanceAccount, error)
221222

223+
// UpdateAccountBalanceAndExpiry updates the balance and/or expiry of an
224+
// account.
225+
UpdateAccountBalanceAndExpiry(ctx context.Context, id AccountID,
226+
newBalance fn.Option[lnwire.MilliSatoshi],
227+
newExpiry fn.Option[time.Time]) error
228+
229+
// AddAccountInvoice adds an invoice hash to an account.
230+
AddAccountInvoice(ctx context.Context, id AccountID,
231+
hash lntypes.Hash) error
232+
233+
// IncreaseAccountBalance increases the balance of the account with the
234+
// given ID by the given amount.
235+
IncreaseAccountBalance(ctx context.Context, id AccountID,
236+
amount lnwire.MilliSatoshi) error
237+
222238
// RemoveAccount finds an account by its ID and removes it from the¨
223239
// store.
224240
RemoveAccount(ctx context.Context, id AccountID) error

accounts/rpcserver.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ func (s *RPCServer) UpdateAccount(ctx context.Context,
122122

123123
// Ask the service to update the account.
124124
account, err := s.service.UpdateAccount(
125-
ctx, accountID, req.AccountBalance, req.ExpirationDate,
125+
ctx, accountID, btcutil.Amount(req.AccountBalance),
126+
req.ExpirationDate,
126127
)
127128
if err != nil {
128129
return nil, err

accounts/service.go

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/btcsuite/btcd/btcutil"
1011
"github.com/btcsuite/btcd/chaincfg"
1112
"github.com/lightninglabs/lndclient"
12-
"github.com/lightninglabs/taproot-assets/fn"
1313
"github.com/lightningnetwork/lnd/channeldb"
14+
"github.com/lightningnetwork/lnd/fn"
1415
invpkg "github.com/lightningnetwork/lnd/invoices"
1516
"github.com/lightningnetwork/lnd/lnrpc"
1617
"github.com/lightningnetwork/lnd/lntypes"
@@ -299,7 +300,7 @@ func (s *InterceptorService) NewAccount(ctx context.Context,
299300
// UpdateAccount writes an account to the database, overwriting the existing one
300301
// if it exists.
301302
func (s *InterceptorService) UpdateAccount(ctx context.Context,
302-
accountID AccountID, accountBalance,
303+
accountID AccountID, accountBalance btcutil.Amount,
303304
expirationDate int64) (*OffChainBalanceAccount, error) {
304305

305306
s.Lock()
@@ -313,36 +314,35 @@ func (s *InterceptorService) UpdateAccount(ctx context.Context,
313314
return nil, ErrAccountServiceDisabled
314315
}
315316

316-
account, err := s.store.Account(ctx, accountID)
317-
if err != nil {
318-
return nil, fmt.Errorf("error fetching account: %w", err)
319-
}
320-
321317
// If the expiration date was set, parse it as a unix time stamp. A
322318
// value of -1 signals "don't update the expiration date".
319+
var expiry fn.Option[time.Time]
323320
if expirationDate > 0 {
324-
account.ExpirationDate = time.Unix(expirationDate, 0)
321+
expiry = fn.Some(time.Unix(expirationDate, 0))
325322
} else if expirationDate == 0 {
326323
// Setting the expiration to 0 means don't expire in which case
327324
// we use a zero time (zero unix time would still be 1970, so
328325
// that doesn't work for us).
329-
account.ExpirationDate = time.Time{}
326+
expiry = fn.Some(time.Time{})
330327
}
331328

332329
// If the new account balance was set, parse it as millisatoshis. A
333330
// value of -1 signals "don't update the balance".
331+
var balance fn.Option[lnwire.MilliSatoshi]
334332
if accountBalance >= 0 {
335333
// Convert from satoshis to millisatoshis for storage.
336-
account.CurrentBalance = int64(accountBalance) * 1000
334+
balance = fn.Some(lnwire.MilliSatoshi(accountBalance) * 1000)
337335
}
338336

339337
// Create the actual account in the macaroon account store.
340-
err = s.store.UpdateAccount(ctx, account)
338+
err := s.store.UpdateAccountBalanceAndExpiry(
339+
ctx, accountID, balance, expiry,
340+
)
341341
if err != nil {
342342
return nil, fmt.Errorf("unable to update account: %w", err)
343343
}
344344

345-
return account, nil
345+
return s.store.Account(ctx, accountID)
346346
}
347347

348348
// Account retrieves an account from the bolt DB and un-marshals it. If the
@@ -439,15 +439,15 @@ func (s *InterceptorService) AssociateInvoice(ctx context.Context, id AccountID,
439439
s.Lock()
440440
defer s.Unlock()
441441

442-
account, err := s.store.Account(ctx, id)
442+
err := s.store.AddAccountInvoice(ctx, id, hash)
443443
if err != nil {
444-
return err
444+
return fmt.Errorf("error adding invoice to account: %w", err)
445445
}
446446

447-
account.Invoices[hash] = struct{}{}
447+
// If the above was successful, then we update our in-memory map.
448448
s.invoiceToAccount[hash] = id
449449

450-
return s.store.UpdateAccount(ctx, account)
450+
return nil
451451
}
452452

453453
// PaymentErrored removes a pending payment from the account's registered
@@ -599,21 +599,13 @@ func (s *InterceptorService) invoiceUpdate(ctx context.Context,
599599
return nil
600600
}
601601

602-
account, err := s.store.Account(ctx, acctID)
603-
if err != nil {
604-
return s.disableAndErrorfUnsafe(
605-
"error fetching account: %w", err,
606-
)
607-
}
608-
609602
// If we get here, the current account has the invoice associated with
610603
// it that was just paid. Credit the amount to the account and update it
611604
// in the DB.
612-
account.CurrentBalance += int64(invoice.AmountPaid)
613-
if err := s.store.UpdateAccount(ctx, account); err != nil {
614-
return s.disableAndErrorfUnsafe(
615-
"error updating account: %w", err,
616-
)
605+
err := s.store.IncreaseAccountBalance(ctx, acctID, invoice.AmountPaid)
606+
if err != nil {
607+
return s.disableAndErrorfUnsafe("error increasing account "+
608+
"balance account: %w", err)
617609
}
618610

619611
// We've now fully processed the invoice and don't need to keep it

accounts/store_kvdb.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ import (
77
"encoding/binary"
88
"encoding/hex"
99
"fmt"
10+
"math"
1011
"os"
1112
"time"
1213

1314
"github.com/btcsuite/btcwallet/walletdb"
15+
"github.com/lightningnetwork/lnd/fn"
1416
"github.com/lightningnetwork/lnd/kvdb"
17+
"github.com/lightningnetwork/lnd/lntypes"
1518
"github.com/lightningnetwork/lnd/lnwire"
1619
"go.etcd.io/bbolt"
1720
)
@@ -194,6 +197,92 @@ func (s *BoltStore) UpdateAccount(_ context.Context,
194197
}, func() {})
195198
}
196199

200+
// UpdateAccountBalanceAndExpiry updates the balance and/or expiry of an
201+
// account.
202+
//
203+
// NOTE: This is part of the Store interface.
204+
func (s *BoltStore) UpdateAccountBalanceAndExpiry(_ context.Context,
205+
id AccountID, newBalance fn.Option[lnwire.MilliSatoshi],
206+
newExpiry fn.Option[time.Time]) error {
207+
208+
update := func(account *OffChainBalanceAccount) error {
209+
newBalance.WhenSome(func(balance lnwire.MilliSatoshi) {
210+
account.CurrentBalance = int64(balance)
211+
})
212+
newExpiry.WhenSome(func(expiry time.Time) {
213+
account.ExpirationDate = expiry
214+
})
215+
216+
return nil
217+
}
218+
219+
return s.updateAccount(id, update)
220+
}
221+
222+
// AddAccountInvoice adds an invoice hash to the account with the given ID.
223+
//
224+
// NOTE: This is part of the Store interface.
225+
func (s *BoltStore) AddAccountInvoice(_ context.Context, id AccountID,
226+
hash lntypes.Hash) error {
227+
228+
update := func(account *OffChainBalanceAccount) error {
229+
account.Invoices[hash] = struct{}{}
230+
231+
return nil
232+
}
233+
234+
return s.updateAccount(id, update)
235+
}
236+
237+
// IncreaseAccountBalance increases the balance of the account with the given ID
238+
// by the given amount.
239+
//
240+
// NOTE: This is part of the Store interface.
241+
func (s *BoltStore) IncreaseAccountBalance(_ context.Context, id AccountID,
242+
amount lnwire.MilliSatoshi) error {
243+
244+
update := func(account *OffChainBalanceAccount) error {
245+
if amount > math.MaxInt64 {
246+
return fmt.Errorf("amount %d exceeds the maximum of %d",
247+
amount, math.MaxInt64)
248+
}
249+
250+
account.CurrentBalance += int64(amount)
251+
252+
return nil
253+
}
254+
255+
return s.updateAccount(id, update)
256+
}
257+
258+
func (s *BoltStore) updateAccount(id AccountID,
259+
updateFn func(*OffChainBalanceAccount) error) error {
260+
261+
return s.db.Update(func(tx kvdb.RwTx) error {
262+
bucket := tx.ReadWriteBucket(accountBucketName)
263+
if bucket == nil {
264+
return ErrAccountBucketNotFound
265+
}
266+
267+
account, err := getAccount(bucket, id)
268+
if err != nil {
269+
return fmt.Errorf("error fetching account, %w", err)
270+
}
271+
272+
err = updateFn(account)
273+
if err != nil {
274+
return fmt.Errorf("error updating account, %w", err)
275+
}
276+
277+
err = storeAccount(bucket, account)
278+
if err != nil {
279+
return fmt.Errorf("error storing account, %w", err)
280+
}
281+
282+
return nil
283+
}, func() {})
284+
}
285+
197286
// storeAccount serializes and writes the given account to the given account
198287
// bucket.
199288
func storeAccount(accountBucket kvdb.RwBucket,
@@ -209,6 +298,19 @@ func storeAccount(accountBucket kvdb.RwBucket,
209298
return accountBucket.Put(account.ID[:], accountBinary)
210299
}
211300

301+
// getAccount retrieves an account from the given account bucket and
302+
// deserializes it.
303+
func getAccount(accountBucket kvdb.RwBucket, id AccountID) (
304+
*OffChainBalanceAccount, error) {
305+
306+
accountBinary := accountBucket.Get(id[:])
307+
if len(accountBinary) == 0 {
308+
return nil, ErrAccNotFound
309+
}
310+
311+
return deserializeAccount(accountBinary)
312+
}
313+
212314
// uniqueRandomAccountID generates a new random ID and makes sure it does not
213315
// yet exist in the DB.
214316
func uniqueRandomAccountID(accountBucket kvdb.RBucket) (AccountID, error) {

0 commit comments

Comments
 (0)