Skip to content

accounts: Add credit and debit account functionality #974

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions accounts/checkers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ type mockService struct {
*requestValuesStore
}

func (m *mockService) CreditAccount(_ context.Context, _ AccountID,
_ lnwire.MilliSatoshi) (*OffChainBalanceAccount, error) {

return nil, nil
}

func (m *mockService) DebitAccount(_ context.Context, _ AccountID,
_ lnwire.MilliSatoshi) (*OffChainBalanceAccount, error) {

return nil, nil
}

func newMockService() *mockService {
return &mockService{
acctBalanceMsat: 0,
Expand Down
10 changes: 10 additions & 0 deletions accounts/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,16 @@ type Service interface {
PaymentErrored(ctx context.Context, id AccountID,
hash lntypes.Hash) error

// CreditAccount increases the balance of an existing account in the
// database.
CreditAccount(ctx context.Context, accountID AccountID,
amount lnwire.MilliSatoshi) (*OffChainBalanceAccount, error)

// DebitAccount decreases the balance of an existing account in the
// database.
DebitAccount(ctx context.Context, accountID AccountID,
amount lnwire.MilliSatoshi) (*OffChainBalanceAccount, error)

RequestValuesStore
}

Expand Down
77 changes: 77 additions & 0 deletions accounts/rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,83 @@ func (s *RPCServer) UpdateAccount(ctx context.Context,
return marshalAccount(account), nil
}

// CreditAccount increases the balance of an existing account in the account
// database, by the given amount.
func (s *RPCServer) CreditAccount(ctx context.Context,
req *litrpc.CreditAccountRequest) (*litrpc.CreditAccountResponse,
error) {

if req.GetAccount() == nil {
return nil, fmt.Errorf("account param must be specified")
}

var id, label string

switch idType := req.Account.Identifier.(type) {
case *litrpc.AccountIdentifier_Id:
id = idType.Id
case *litrpc.AccountIdentifier_Label:
label = idType.Label
}

log.Infof("[creditaccount] id=%s, label=%v, amount=%d", id, label,
req.Amount)

amount := lnwire.MilliSatoshi(req.Amount * 1000)

accountID, err := s.findAccount(ctx, id, label)
if err != nil {
return nil, err
}

account, err := s.service.CreditAccount(ctx, accountID, amount)
if err != nil {
return nil, err
}

return &litrpc.CreditAccountResponse{
Account: marshalAccount(account),
}, nil
}

// DebitAccount decreases the balance of an existing account in the account
// database, by the given amount.
func (s *RPCServer) DebitAccount(ctx context.Context,
req *litrpc.DebitAccountRequest) (*litrpc.DebitAccountResponse, error) {

if req.GetAccount() == nil {
return nil, fmt.Errorf("account param must be specified")
}

var id, label string

switch idType := req.Account.Identifier.(type) {
case *litrpc.AccountIdentifier_Id:
id = idType.Id
case *litrpc.AccountIdentifier_Label:
label = idType.Label
}

log.Infof("[debitaccount] id=%s, label=%v, amount=%d", id, label,
req.Amount)

amount := lnwire.MilliSatoshi(req.Amount * 1000)

accountID, err := s.findAccount(ctx, id, label)
if err != nil {
return nil, err
}

account, err := s.service.DebitAccount(ctx, accountID, amount)
if err != nil {
return nil, err
}

return &litrpc.DebitAccountResponse{
Account: marshalAccount(account),
}, nil
}

// ListAccounts returns all accounts that are currently stored in the account
// database.
func (s *RPCServer) ListAccounts(ctx context.Context,
Expand Down
50 changes: 50 additions & 0 deletions accounts/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,56 @@ func (s *InterceptorService) UpdateAccount(ctx context.Context,
return s.store.Account(ctx, accountID)
}

// CreditAccount increases the balance of an existing account in the database.
func (s *InterceptorService) CreditAccount(ctx context.Context,
accountID AccountID,
amount lnwire.MilliSatoshi) (*OffChainBalanceAccount, error) {

s.Lock()
defer s.Unlock()

// As this function updates account balances, we require that the
// service is running before we execute it.
if !s.isRunningUnsafe() {
// This case can only happen if the service is disabled while
// we're processing a request.
return nil, ErrAccountServiceDisabled
}

// Credit the account in the db.
err := s.store.CreditAccount(ctx, accountID, amount)
if err != nil {
return nil, fmt.Errorf("unable to credit account: %w", err)
}

return s.store.Account(ctx, accountID)
}

// DebitAccount decreases the balance of an existing account in the database.
func (s *InterceptorService) DebitAccount(ctx context.Context,
accountID AccountID,
amount lnwire.MilliSatoshi) (*OffChainBalanceAccount, error) {

s.Lock()
defer s.Unlock()

// As this function updates account balances, we require that the
// service is running before we execute it.
if !s.isRunningUnsafe() {
// This case can only happen if the service is disabled while
// we're processing a request.
return nil, ErrAccountServiceDisabled
}

// Debit the account in the db.
err := s.store.DebitAccount(ctx, accountID, amount)
if err != nil {
return nil, fmt.Errorf("unable to debit account: %w", err)
}

return s.store.Account(ctx, accountID)
}

// Account retrieves an account from the bolt DB and un-marshals it. If the
// account cannot be found, then ErrAccNotFound is returned.
func (s *InterceptorService) Account(ctx context.Context,
Expand Down
131 changes: 131 additions & 0 deletions app/src/types/generated/lit-accounts_pb.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading