pool/marshaler.go
positiveblue 1589efe1ea
rpcserver: add Marshaler interface
The Marshaler interface is used to transform internal types to
decorated RPC ones.

It decouples that functionality form the rpcServer so it is easier to
test exhaustively.
2021-12-14 20:40:02 -08:00

106 lines
3 KiB
Go

package pool
import (
"context"
"fmt"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/pool/account"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/poolrpc"
"github.com/lightninglabs/pool/terms"
)
// marshalerConfig contains all of the marshaler's dependencies in order to
// carry out its duties.
type marshalerConfig struct {
// GetOrders returns all orders that are currently known to the store.
GetOrders func() ([]order.Order, error)
// Terms returns the current dynamic auctioneer terms like max account
// size, max order duration in blocks and the auction fee schedule.
Terms func(ctx context.Context) (*terms.AuctioneerTerms, error)
}
// marshaler is an internal struct type that implements the Marshaler interface.
type marshaler struct {
cfg *marshalerConfig
}
// NewMarshaler returns an internal type that implements the Marshaler interface.
func NewMarshaler(cfg *marshalerConfig) *marshaler { // nolint:golint
return &marshaler{
cfg: cfg,
}
}
// MarshallAccountsWithAvailableBalance returns the RPC representation of an account
// with the account.AvailableBalance value populated.
func (m *marshaler) MarshallAccountsWithAvailableBalance(ctx context.Context,
accounts []*account.Account) ([]*poolrpc.Account, error) {
rpcAccounts := make([]*poolrpc.Account, 0, len(accounts))
for _, acct := range accounts {
rpcAccount, err := MarshallAccount(acct)
if err != nil {
return nil, err
}
rpcAccounts = append(rpcAccounts, rpcAccount)
}
// For each account, we'll need to compute the available balance, which
// requires us to sum up all the debits from outstanding orders.
orders, err := m.cfg.GetOrders()
if err != nil {
return nil, err
}
// Get the current fee schedule so we can compute the worst-case
// account debit assuming all our standing orders were matched.
auctionTerms, err := m.cfg.Terms(ctx)
if err != nil {
return nil, fmt.Errorf("unable to query auctioneer terms: %v",
err)
}
// For each active account, consume the worst-case account delta if the
// order were to be matched.
accountDebits := make(map[[33]byte]btcutil.Amount)
auctionFeeSchedule := auctionTerms.FeeSchedule()
for _, acct := range accounts {
var (
debitAmt btcutil.Amount
acctKey [33]byte
)
copy(
acctKey[:],
acct.TraderKey.PubKey.SerializeCompressed(),
)
// We'll make sure to accumulate a distinct sum for each
// outstanding account the user has.
for _, o := range orders {
if o.Details().AcctKey != acctKey {
continue
}
debitAmt += o.ReservedValue(auctionFeeSchedule)
}
accountDebits[acctKey] = debitAmt
}
// Finally, we'll populate the available balance value for each of the
// existing accounts.
for _, rpcAccount := range rpcAccounts {
var acctKey [33]byte
copy(acctKey[:], rpcAccount.TraderKey)
accountDebit := accountDebits[acctKey]
availableBalance := rpcAccount.Value - uint64(accountDebit)
rpcAccount.AvailableBalance = availableBalance
}
return rpcAccounts, nil
}