accounts

package
v0.12.4-alpha Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2024 License: MIT Imports: 35 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DBFilename is the filename within the data directory which contains
	// the macaroon stores.
	DBFilename = "accounts.db"

	// DefaultAccountDBTimeout is the default maximum time we wait for the
	// account bbolt database to be opened. If the database is already
	// opened by another process, the unique lock cannot be obtained. With
	// the timeout we error out after the given time instead of just
	// blocking for forever.
	DefaultAccountDBTimeout = 5 * time.Second
)
View Source
const (
	// AccountIDLen is the length of the ID that is generated as a unique
	// identifier of an account. It is 8 bytes long so guessing is
	// improbable, but it's still not mistaken for a SHA256 hash.
	AccountIDLen = 8
)
View Source
const (
	// CondAccount is the custom caveat condition that binds a macaroon to a
	// certain account.
	CondAccount = "account"
)
View Source
const Subsystem = "ACCT"

Variables

View Source
var (
	// DecodePayReqPassThrough is a pass-through checker that allows calls
	// to DecodePayReq through unchanged.
	DecodePayReqPassThrough = mid.NewPassThrough(
		&lnrpc.PayReqString{}, &lnrpc.PayReq{},
	)

	// GetNodeInfoPassThrough is a pass-through checker that allows calls
	// to GetNodeInfo through unchanged.
	GetNodeInfoPassThrough = mid.NewPassThrough(
		&lnrpc.NodeInfoRequest{}, &lnrpc.NodeInfo{},
	)

	// PendingChannelsEmptyRewriter is a response re-writer that returns a
	// response to PendingChannels with zero channels shown.
	PendingChannelsEmptyRewriter = mid.NewResponseEmptier[
		*lnrpc.PendingChannelsRequest, *lnrpc.PendingChannelsResponse,
	]()

	// ListChannelsEmptyRewriter is a response re-writer that returns a
	// response to ListChannels with zero channels shown.
	ListChannelsEmptyRewriter = mid.NewResponseEmptier[
		*lnrpc.ListChannelsRequest, *lnrpc.ListChannelsResponse,
	]()

	// ClosedChannelsEmptyRewriter is a response re-writer that returns a
	// response to ClosedChannels with zero channels shown.
	ClosedChannelsEmptyRewriter = mid.NewResponseEmptier[
		*lnrpc.ClosedChannelsRequest, *lnrpc.ClosedChannelsResponse,
	]()

	// WalletBalanceEmptyRewriter is a response re-writer that returns a
	// response to WalletBalance with a zero balance shown.
	WalletBalanceEmptyRewriter = mid.NewResponseEmptier[
		*lnrpc.WalletBalanceRequest, *lnrpc.WalletBalanceResponse,
	]()

	// GetTransactionsEmptyRewriter is a response re-writer that returns a
	// response to GetTransactions with zero transactions shown.
	GetTransactionsEmptyRewriter = mid.NewResponseEmptier[
		*lnrpc.GetTransactionsRequest, *lnrpc.TransactionDetails,
	]()

	// ListPeersEmptyRewriter is a response re-writer that returns a
	// response to ListPeers with zero peers shown.
	ListPeersEmptyRewriter = mid.NewResponseEmptier[
		*lnrpc.ListPeersRequest, *lnrpc.ListPeersResponse,
	]()
)
View Source
var (
	// ErrAccountBucketNotFound specifies that there is no bucket for the
	// accounts in the DB yet which can/should only happen if the account
	// store has been corrupted or was initialized incorrectly.
	ErrAccountBucketNotFound = errors.New("account bucket not found")

	// ErrAccNotFound is returned if an account could not be found in the
	// local bolt DB.
	ErrAccNotFound = errors.New("account not found")

	// ErrNoInvoiceIndexKnown is the error that is returned by the store if
	// it does not yet have any invoice indexes stored.
	ErrNoInvoiceIndexKnown = errors.New("no invoice index known")

	// ErrAccExpired is returned if an account has an expiration date set
	// and that date is in the past.
	ErrAccExpired = errors.New("account has expired")

	// ErrAccBalanceInsufficient is returned if the amount required to
	// perform a certain action is larger than the current balance of the
	// account
	ErrAccBalanceInsufficient = errors.New("account balance insufficient")

	// ErrNotSupportedWithAccounts is the error that is returned when an RPC
	// is called that isn't supported to be handled by the account
	// interceptor.
	ErrNotSupportedWithAccounts = errors.New("this RPC call is not " +
		"supported with restricted account macaroons")

	// ErrAccountServiceDisabled is the error that is returned when the
	// account service has been disabled due to an error being thrown
	// in the service that cannot be recovered from.
	ErrAccountServiceDisabled = errors.New("the account service has been " +
		"stopped")

	// MacaroonPermissions are the permissions required for an account
	// macaroon.
	MacaroonPermissions = []bakery.Op{{
		Entity: "info",
		Action: "read",
	}, {
		Entity: "offchain",
		Action: "read",
	}, {
		Entity: "offchain",
		Action: "write",
	}, {
		Entity: "onchain",
		Action: "read",
	}, {
		Entity: "invoices",
		Action: "read",
	}, {
		Entity: "invoices",
		Action: "write",
	}, {
		Entity: "peers",
		Action: "read",
	}}
)
View Source
var (
	// KeyAccount is the key under which we store the account in the request
	// context.
	KeyAccount = ContextKey{"account"}
)

Functions

func AddToContext

func AddToContext(ctx context.Context, key ContextKey,
	value *OffChainBalanceAccount) context.Context

AddToContext adds the given value to the context for easy retrieval later on.

func FromContext

func FromContext(ctx context.Context, key ContextKey) interface{}

FromContext tries to extract a value from the given context.

func InvoiceEntryMapDecoder

func InvoiceEntryMapDecoder(r io.Reader, val any, buf *[8]byte,
	_ uint64) error

InvoiceEntryMapDecoder decodes a map of invoice hashes.

func InvoiceEntryMapEncoder

func InvoiceEntryMapEncoder(w io.Writer, val any, buf *[8]byte) error

InvoiceEntryMapEncoder encodes a map of invoice hashes.

func PaymentEntryMapDecoder

func PaymentEntryMapDecoder(r io.Reader, val any, buf *[8]byte, _ uint64) error

PaymentEntryMapDecoder decodes a map of payment entries.

func PaymentEntryMapEncoder

func PaymentEntryMapEncoder(w io.Writer, val any, buf *[8]byte) error

PaymentEntryMapEncoder encodes a map of payment entries.

func UseLogger

func UseLogger(logger btclog.Logger)

UseLogger uses a specified Logger to output package logging info. This should be used in preference to SetLogWriter if the caller is also using btclog.

Types

type AccountChecker

type AccountChecker struct {
	// contains filtered or unexported fields
}

AccountChecker is a type that can check all account related requests, including invoices, payments and account balances.

func NewAccountChecker

func NewAccountChecker(service Service,
	chainParams *chaincfg.Params) *AccountChecker

NewAccountChecker creates a new account checker that can keep track of all account related requests, including invoices, payments and account balances.

type AccountID

type AccountID [AccountIDLen]byte

AccountID represents an account's unique ID.

func ParseAccountID

func ParseAccountID(idStr string) (*AccountID, error)

ParseAccountID attempts to parse a string as an account ID.

type AccountInvoices

type AccountInvoices map[lntypes.Hash]struct{}

AccountInvoices is the set of invoices that are associated with an account.

type AccountPayments

type AccountPayments map[lntypes.Hash]*PaymentEntry

AccountPayments is the set of payments that are associated with an account.

type AccountType

type AccountType uint8

AccountType is an enum-like type which denotes the possible account types that can be referenced in macaroons to keep track of user's balances.

const (
	// TypeInitialBalance represents an account that has an initial balance
	// that is used up when it is spent and is not replenished
	// automatically.
	TypeInitialBalance AccountType = 0
)

type BoltStore

type BoltStore struct {
	// contains filtered or unexported fields
}

BoltStore wraps the bolt DB that stores all accounts and their balances.

func NewBoltStore

func NewBoltStore(dir, fileName string) (*BoltStore, error)

NewBoltStore creates a BoltStore instance and the corresponding bucket in the bolt DB if it does not exist yet.

func (*BoltStore) Account

func (s *BoltStore) Account(id AccountID) (*OffChainBalanceAccount, error)

Account retrieves an account from the bolt DB and un-marshals it. If the account cannot be found, then ErrAccNotFound is returned.

func (*BoltStore) Accounts

func (s *BoltStore) Accounts() ([]*OffChainBalanceAccount, error)

Accounts retrieves all accounts from the bolt DB and un-marshals them.

func (*BoltStore) Close

func (s *BoltStore) Close() error

Close closes the underlying bolt DB.

func (*BoltStore) LastIndexes

func (s *BoltStore) LastIndexes() (uint64, uint64, error)

LastIndexes returns the last invoice add and settle index or ErrNoInvoiceIndexKnown if no indexes are known yet.

func (*BoltStore) NewAccount

func (s *BoltStore) NewAccount(balance lnwire.MilliSatoshi,
	expirationDate time.Time, label string) (*OffChainBalanceAccount,
	error)

NewAccount creates a new OffChainBalanceAccount with the given balance and a randomly chosen ID.

func (*BoltStore) RemoveAccount

func (s *BoltStore) RemoveAccount(id AccountID) error

RemoveAccount finds an account by its ID and removes it from the DB.

func (*BoltStore) StoreLastIndexes

func (s *BoltStore) StoreLastIndexes(addIndex, settleIndex uint64) error

StoreLastIndexes stores the last invoice add and settle index.

func (*BoltStore) UpdateAccount

func (s *BoltStore) UpdateAccount(account *OffChainBalanceAccount) error

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

type CheckerMap

type CheckerMap map[string]mid.RoundTripChecker

CheckerMap is a type alias that maps gRPC request URIs to their rpcmiddleware.RoundTripChecker types.

type Config

type Config struct {
	// Disable will disable the accounts service if set.
	Disable bool `long:"disable" description:"disable the accounts service"`
}

Config holds the configuration options for the accounts service.

type ContextKey

type ContextKey struct {
	Name string
}

ContextKey is the type that we use to identify account specific values in the request context. We wrap the string inside a struct because of this comment in the context API: "The provided key must be comparable and should not be of type string or any other built-in type to avoid collisions between packages using context."

type InterceptorService

type InterceptorService struct {
	// RWMutex is the read/write mutex that guards all fields that can be
	// accessed by multiple goroutines at the same time, such as the store
	// or pending payments.
	sync.RWMutex
	// contains filtered or unexported fields
}

InterceptorService is an account storage and interceptor for accounting based macaroon balances and utility methods to manage accounts.

func NewService

func NewService(dir string,
	errCallback func(error)) (*InterceptorService, error)

NewService returns a service backed by the macaroon Bolt DB stored in the passed-in directory.

func (*InterceptorService) Account

Account retrieves an account from the bolt DB and un-marshals it. If the account cannot be found, then ErrAccNotFound is returned.

func (*InterceptorService) Accounts

func (s *InterceptorService) Accounts() ([]*OffChainBalanceAccount, error)

Accounts retrieves all accounts from the bolt DB and un-marshals them.

func (*InterceptorService) AssociateInvoice

func (s *InterceptorService) AssociateInvoice(id AccountID,
	hash lntypes.Hash) error

AssociateInvoice associates a generated invoice with the given account, making it possible for the account to be credited in case the invoice is paid.

func (*InterceptorService) AssociatePayment

func (s *InterceptorService) AssociatePayment(id AccountID,
	paymentHash lntypes.Hash, fullAmt lnwire.MilliSatoshi) error

AssociatePayment associates a payment (hash) with the given account, ensuring that the payment will be tracked for a user when LiT is restarted.

func (*InterceptorService) CheckBalance

func (s *InterceptorService) CheckBalance(id AccountID,
	requiredBalance lnwire.MilliSatoshi) error

CheckBalance ensures an account is valid and has a balance equal to or larger than the amount that is required.

func (*InterceptorService) CustomCaveatName

func (s *InterceptorService) CustomCaveatName() string

CustomCaveatName returns the name of the custom caveat that is expected to be handled by this interceptor. Cannot be specified in read-only mode.

func (*InterceptorService) Intercept

Intercept processes an RPC middleware interception request and returns the interception result which either accepts or rejects the intercepted message.

func (*InterceptorService) IsRunning

func (s *InterceptorService) IsRunning() bool

IsRunning checks if the account service is running, and returns a boolean indicating whether it is running or not.

func (*InterceptorService) Name

func (s *InterceptorService) Name() string

Name returns the name of the interceptor.

func (*InterceptorService) NewAccount

func (s *InterceptorService) NewAccount(balance lnwire.MilliSatoshi,
	expirationDate time.Time, label string) (*OffChainBalanceAccount,
	error)

NewAccount creates a new OffChainBalanceAccount with the given balance and a randomly chosen ID.

func (*InterceptorService) ReadOnly

func (s *InterceptorService) ReadOnly() bool

ReadOnly returns true if this interceptor should be registered in read-only mode. In read-only mode no custom caveat name can be specified.

func (*InterceptorService) RemoveAccount

func (s *InterceptorService) RemoveAccount(id AccountID) error

RemoveAccount finds an account by its ID and removes it from the DB.

func (*InterceptorService) RemovePayment

func (s *InterceptorService) RemovePayment(hash lntypes.Hash) error

RemovePayment removes a failed payment from the service because it no longer needs to be tracked. The payment is certain to never succeed, so we never need to debit the amount from the account.

func (*InterceptorService) Start

func (s *InterceptorService) Start(lightningClient lndclient.LightningClient,
	routerClient lndclient.RouterClient, params *chaincfg.Params) error

Start starts the account service and its interceptor capability.

func (*InterceptorService) Stop

func (s *InterceptorService) Stop() error

Stop shuts down the account service.

func (*InterceptorService) TrackPayment

func (s *InterceptorService) TrackPayment(id AccountID, hash lntypes.Hash,
	fullAmt lnwire.MilliSatoshi) error

TrackPayment adds a new payment to be tracked to the service. If the payment is eventually settled, its amount needs to be debited from the given account.

func (*InterceptorService) UpdateAccount

func (s *InterceptorService) UpdateAccount(accountID AccountID, accountBalance,
	expirationDate int64) (*OffChainBalanceAccount, error)

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

type OffChainBalanceAccount

type OffChainBalanceAccount struct {
	// ID is the randomly generated account identifier.
	ID AccountID

	// Type is the account type.
	Type AccountType

	// InitialBalance stores the initial balance in millisatoshis and is
	// never updated.
	InitialBalance lnwire.MilliSatoshi

	// CurrentBalance is the currently available balance of the account
	// in millisatoshis that is updated every time an invoice is paid. This
	// value can be negative (for example if the fees for a payment are
	// larger than the estimate made when checking the balance and the
	// account is close to zero value).
	CurrentBalance int64

	// LastUpdate keeps track of the last time the balance of the account
	// was updated.
	LastUpdate time.Time

	// ExpirationDate is a specific date in the future after which the
	// account is marked as expired. Can be set to zero for accounts that
	// never expire.
	ExpirationDate time.Time

	// Invoices is a list of all invoices that are associated with the
	// account.
	Invoices AccountInvoices

	// Payments is a list of all payments that are associated with the
	// account and the last status we were aware of.
	Payments AccountPayments

	// Label is an optional label that can be set for the account. If it is
	// not empty then it must be unique.
	Label string
}

OffChainBalanceAccount holds all information that is needed to keep track of a user's off-chain account balance. This balance can only be spent by paying invoices.

func AccountFromContext

func AccountFromContext(ctx context.Context) (*OffChainBalanceAccount, error)

AccountFromContext attempts to extract an account from the given context.

func (*OffChainBalanceAccount) CurrentBalanceSats

func (a *OffChainBalanceAccount) CurrentBalanceSats() int64

CurrentBalanceSats returns the current account balance in satoshis.

func (*OffChainBalanceAccount) HasExpired

func (a *OffChainBalanceAccount) HasExpired() bool

HasExpired returns true if the account has an expiration date set and that date is in the past.

type PaymentEntry

type PaymentEntry struct {
	// Status is the RPC status of the payment as reported by lnd.
	Status lnrpc.Payment_PaymentStatus

	// FullAmount is the total amount of the payment which includes the
	// payment amount and the estimated routing fee. The routing fee is
	// set to the fee limit set when sending the payment and updated to the
	// actual routing fee when the payment settles.
	FullAmount lnwire.MilliSatoshi
}

PaymentEntry is the data we track per payment that is associated with an account. This basically includes all information required to make sure in-flight payments don't exceed the total available account balance.

type RPCServer

type RPCServer struct {
	litrpc.UnimplementedAccountsServer
	// contains filtered or unexported fields
}

RPCServer is the main server that implements the Accounts gRPC service.

func NewRPCServer

func NewRPCServer(service *InterceptorService,
	superMacBaker session.MacaroonBaker) *RPCServer

NewRPCServer returns a new RPC server for the given service.

func (*RPCServer) AccountInfo

func (s *RPCServer) AccountInfo(_ context.Context,
	req *litrpc.AccountInfoRequest) (*litrpc.Account, error)

AccountInfo returns the account with the given ID or label.

func (*RPCServer) CreateAccount

CreateAccount adds an entry to the account database. This entry represents an amount of satoshis (account balance) that can be spent using off-chain transactions (e.g. paying invoices).

Macaroons can be created to be locked to an account. This makes sure that the bearer of the macaroon can only spend at most that amount of satoshis through the daemon that has issued the macaroon.

Accounts only assert a maximum amount spendable. Having a certain account balance does not guarantee that the node has the channel liquidity to actually spend that amount.

func (*RPCServer) ListAccounts

ListAccounts returns all accounts that are currently stored in the account database.

func (*RPCServer) RemoveAccount

RemoveAccount removes the given account from the account database.

func (*RPCServer) UpdateAccount

func (s *RPCServer) UpdateAccount(_ context.Context,
	req *litrpc.UpdateAccountRequest) (*litrpc.Account, error)

UpdateAccount updates an existing account in the account database.

type Service

type Service interface {
	// CheckBalance ensures an account is valid and has a balance equal to
	// or larger than the amount that is required.
	CheckBalance(id AccountID, requiredBalance lnwire.MilliSatoshi) error

	// AssociateInvoice associates a generated invoice with the given
	// account, making it possible for the account to be credited in case
	// the invoice is paid.
	AssociateInvoice(id AccountID, hash lntypes.Hash) error

	// TrackPayment adds a new payment to be tracked to the service. If the
	// payment is eventually settled, its amount needs to be debited from
	// the given account.
	TrackPayment(id AccountID, hash lntypes.Hash,
		fullAmt lnwire.MilliSatoshi) error

	// RemovePayment removes a failed payment from the service because it no
	// longer needs to be tracked. The payment is certain to never succeed,
	// so we never need to debit the amount from the account.
	RemovePayment(hash lntypes.Hash) error

	// AssociatePayment associates a payment (hash) with the given account,
	// ensuring that the payment will be tracked for a user when LiT is
	// restarted.
	AssociatePayment(id AccountID, paymentHash lntypes.Hash,
		fullAmt lnwire.MilliSatoshi) error
}

Service is the main account service interface.

type Store

type Store interface {
	// NewAccount creates a new OffChainBalanceAccount with the given
	// balance and a randomly chosen ID.
	NewAccount(balance lnwire.MilliSatoshi, expirationDate time.Time,
		label string) (*OffChainBalanceAccount, error)

	// UpdateAccount writes an account to the database, overwriting the
	// existing one if it exists.
	UpdateAccount(account *OffChainBalanceAccount) error

	// Account retrieves an account from the Store and un-marshals it. If
	// the account cannot be found, then ErrAccNotFound is returned.
	Account(id AccountID) (*OffChainBalanceAccount, error)

	// Accounts retrieves all accounts from the store and un-marshals them.
	Accounts() ([]*OffChainBalanceAccount, error)

	// RemoveAccount finds an account by its ID and removes it from the¨
	// store.
	RemoveAccount(id AccountID) error

	// LastIndexes returns the last invoice add and settle index or
	// ErrNoInvoiceIndexKnown if no indexes are known yet.
	LastIndexes() (uint64, uint64, error)

	// StoreLastIndexes stores the last invoice add and settle index.
	StoreLastIndexes(addIndex, settleIndex uint64) error

	// Close closes the underlying store.
	Close() error
}

Store is the main account store interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL