Skip to content

Commit 59563c8

Browse files
committed
accounts: add label to account
1 parent b05e640 commit 59563c8

File tree

7 files changed

+59
-9
lines changed

7 files changed

+59
-9
lines changed

accounts/interface.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ type OffChainBalanceAccount struct {
104104
// Payments is a list of all payments that are associated with the
105105
// account and the last status we were aware of.
106106
Payments map[lntypes.Hash]*PaymentEntry
107+
108+
// Label is an optional label that can be set for the account. If it is
109+
// not empty then it must be unique.
110+
Label string
107111
}
108112

109113
// HasExpired returns true if the account has an expiration date set and that
@@ -180,8 +184,8 @@ var (
180184
type Store interface {
181185
// NewAccount creates a new OffChainBalanceAccount with the given
182186
// balance and a randomly chosen ID.
183-
NewAccount(balance lnwire.MilliSatoshi,
184-
expirationDate time.Time) (*OffChainBalanceAccount, error)
187+
NewAccount(balance lnwire.MilliSatoshi, expirationDate time.Time,
188+
label string) (*OffChainBalanceAccount, error)
185189

186190
// UpdateAccount writes an account to the database, overwriting the
187191
// existing one if it exists.

accounts/rpcserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (s *RPCServer) CreateAccount(ctx context.Context,
7070
balanceMsat = lnwire.NewMSatFromSatoshis(balance)
7171

7272
// Create the actual account in the macaroon account store.
73-
account, err := s.service.NewAccount(balanceMsat, expirationDate)
73+
account, err := s.service.NewAccount(balanceMsat, expirationDate, "")
7474
if err != nil {
7575
return nil, fmt.Errorf("unable to create account: %v", err)
7676
}

accounts/service.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,13 @@ func (s *InterceptorService) Start(lightningClient lndclient.LightningClient,
212212
// NewAccount creates a new OffChainBalanceAccount with the given balance and a
213213
// randomly chosen ID.
214214
func (s *InterceptorService) NewAccount(balance lnwire.MilliSatoshi,
215-
expirationDate time.Time) (*OffChainBalanceAccount, error) {
215+
expirationDate time.Time, label string) (*OffChainBalanceAccount,
216+
error) {
216217

217218
s.Lock()
218219
defer s.Unlock()
219220

220-
return s.store.NewAccount(balance, expirationDate)
221+
return s.store.NewAccount(balance, expirationDate, label)
221222
}
222223

223224
// UpdateAccount writes an account to the database, overwriting the existing one

accounts/service_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ func TestAccountService(t *testing.T) {
206206
}, {
207207
name: "startup do not track completed payments",
208208
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
209-
acct, err := s.store.NewAccount(1234, testExpiration)
209+
acct, err := s.store.NewAccount(
210+
1234, testExpiration, "",
211+
)
210212
require.NoError(t, err)
211213

212214
acct.Invoices[testHash] = struct{}{}

accounts/store.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"crypto/rand"
66
"encoding/binary"
7+
"encoding/hex"
78
"fmt"
89
"os"
910
"time"
@@ -104,12 +105,39 @@ func (s *BoltStore) Close() error {
104105
// NewAccount creates a new OffChainBalanceAccount with the given balance and a
105106
// randomly chosen ID.
106107
func (s *BoltStore) NewAccount(balance lnwire.MilliSatoshi,
107-
expirationDate time.Time) (*OffChainBalanceAccount, error) {
108+
expirationDate time.Time, label string) (*OffChainBalanceAccount,
109+
error) {
108110

109111
if balance == 0 {
110112
return nil, fmt.Errorf("a new account cannot have balance of 0")
111113
}
112114

115+
// If a label is set, it must be unique, as we use it to identify the
116+
// account in some of the RPCs. It also can't be mistaken for a hex
117+
// encoded account ID to avoid confusion and make it easier for the CLI
118+
// to distinguish between the two.
119+
if len(label) > 0 {
120+
if _, err := hex.DecodeString(label); err == nil &&
121+
len(label) == hex.EncodedLen(AccountIDLen) {
122+
123+
return nil, fmt.Errorf("the label '%s' is not allowed "+
124+
"as it can be mistaken for an account ID",
125+
label)
126+
}
127+
128+
accounts, err := s.Accounts()
129+
if err != nil {
130+
return nil, fmt.Errorf("error checking label "+
131+
"uniqueness: %w", err)
132+
}
133+
for _, account := range accounts {
134+
if account.Label == label {
135+
return nil, fmt.Errorf("an account with the "+
136+
"label '%s' already exists", label)
137+
}
138+
}
139+
}
140+
113141
// First, create a new instance of an account. Currently, only the type
114142
// TypeInitialBalance is supported.
115143
account := &OffChainBalanceAccount{
@@ -120,6 +148,7 @@ func (s *BoltStore) NewAccount(balance lnwire.MilliSatoshi,
120148
LastUpdate: time.Now(),
121149
Invoices: make(map[lntypes.Hash]struct{}),
122150
Payments: make(map[lntypes.Hash]*PaymentEntry),
151+
Label: label,
123152
}
124153

125154
// Try storing the account in the account database, so we can keep track

accounts/store_test.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ func TestAccountStore(t *testing.T) {
1818

1919
// An initial balance of 0 is not allowed, but later we can reach a
2020
// zero balance.
21-
_, err = store.NewAccount(0, time.Time{})
21+
_, err = store.NewAccount(0, time.Time{}, "")
2222
require.ErrorContains(t, err, "cannot have balance of 0")
2323

2424
// Create an account that does not expire.
25-
acct1, err := store.NewAccount(123, time.Time{})
25+
acct1, err := store.NewAccount(123, time.Time{}, "foo")
2626
require.NoError(t, err)
2727
require.False(t, acct1.HasExpired())
2828

@@ -31,6 +31,14 @@ func TestAccountStore(t *testing.T) {
3131

3232
assertEqualAccounts(t, acct1, dbAccount)
3333

34+
// Make sure we cannot create a second account with the same label.
35+
_, err = store.NewAccount(123, time.Time{}, "foo")
36+
require.ErrorContains(t, err, "account with the label 'foo' already")
37+
38+
// Make sure we cannot set a label that looks like an account ID.
39+
_, err = store.NewAccount(123, time.Time{}, "0011223344556677")
40+
require.ErrorContains(t, err, "is not allowed as it can be mistaken")
41+
3442
// Update all values of the account that we can modify.
3543
acct1.CurrentBalance = -500
3644
acct1.ExpirationDate = time.Now()

accounts/tlv.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const (
2121
typeExpirationDate tlv.Type = 6
2222
typeInvoices tlv.Type = 7
2323
typePayments tlv.Type = 8
24+
typeLabel tlv.Type = 9
2425
)
2526

2627
func serializeAccount(account *OffChainBalanceAccount) ([]byte, error) {
@@ -34,6 +35,7 @@ func serializeAccount(account *OffChainBalanceAccount) ([]byte, error) {
3435
initialBalance = uint64(account.InitialBalance)
3536
currentBalance = uint64(account.CurrentBalance)
3637
lastUpdate = uint64(account.LastUpdate.UnixNano())
38+
label = []byte(account.Label)
3739
)
3840

3941
tlvRecords := []tlv.Record{
@@ -55,6 +57,7 @@ func serializeAccount(account *OffChainBalanceAccount) ([]byte, error) {
5557
tlvRecords,
5658
newHashMapRecord(typeInvoices, &account.Invoices),
5759
newPaymentEntryMapRecord(typePayments, &account.Payments),
60+
tlv.MakePrimitiveRecord(typeLabel, &label),
5861
)
5962

6063
tlvStream, err := tlv.NewStream(tlvRecords...)
@@ -80,6 +83,7 @@ func deserializeAccount(content []byte) (*OffChainBalanceAccount, error) {
8083
expirationDate uint64
8184
invoices map[lntypes.Hash]struct{}
8285
payments map[lntypes.Hash]*PaymentEntry
86+
label []byte
8387
)
8488

8589
tlvStream, err := tlv.NewStream(
@@ -91,6 +95,7 @@ func deserializeAccount(content []byte) (*OffChainBalanceAccount, error) {
9195
tlv.MakePrimitiveRecord(typeExpirationDate, &expirationDate),
9296
newHashMapRecord(typeInvoices, &invoices),
9397
newPaymentEntryMapRecord(typePayments, &payments),
98+
tlv.MakePrimitiveRecord(typeLabel, &label),
9499
)
95100
if err != nil {
96101
return nil, err
@@ -108,6 +113,7 @@ func deserializeAccount(content []byte) (*OffChainBalanceAccount, error) {
108113
LastUpdate: time.Unix(0, int64(lastUpdate)),
109114
Invoices: invoices,
110115
Payments: payments,
116+
Label: string(label),
111117
}
112118
copy(account.ID[:], id)
113119

0 commit comments

Comments
 (0)