diff --git a/gen.go b/gen.go index 28917b7..0915509 100644 --- a/gen.go +++ b/gen.go @@ -5,8 +5,13 @@ package pool // make mock // +//go:generate mockgen -source=interfaces.go -package=pool -destination=mock_interfaces.go + //go:generate mockgen -source=sidecar/interfaces.go -package=sidecar -destination=sidecar/mock_interfaces.go + //go:generate mockgen -source=internal/test/interfaces.go -package=test -destination=internal/test/mock_interfaces.go + //go:generate mockgen -source=account/interfaces.go -package=account -destination=account/mock_interfaces.go //go:generate mockgen -source=account/watcher/interfaces.go -package=watcher -destination=account/watcher/mock_interface_test.go + //go:generate mockgen -source=order/interfaces.go -package=order -destination=order/mock_interfaces.go diff --git a/interfaces.go b/interfaces.go new file mode 100644 index 0000000..4f15c84 --- /dev/null +++ b/interfaces.go @@ -0,0 +1,16 @@ +package pool + +import ( + "context" + + "github.com/lightninglabs/pool/account" + "github.com/lightninglabs/pool/poolrpc" +) + +// Marshaler interface to transform internal types to decorated RPC ones. +type Marshaler interface { + // MarshallAccountsWithAvailableBalance returns the RPC representation + // of an account with the account.AvailableBalance value populated. + MarshallAccountsWithAvailableBalance(ctx context.Context, + accounts []*account.Account) ([]*poolrpc.Account, error) +} diff --git a/marshaler.go b/marshaler.go new file mode 100644 index 0000000..9b3a39a --- /dev/null +++ b/marshaler.go @@ -0,0 +1,106 @@ +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 +} diff --git a/mock_interfaces.go b/mock_interfaces.go new file mode 100644 index 0000000..3f91527 --- /dev/null +++ b/mock_interfaces.go @@ -0,0 +1,52 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: interfaces.go + +// Package pool is a generated GoMock package. +package pool + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + account "github.com/lightninglabs/pool/account" + poolrpc "github.com/lightninglabs/pool/poolrpc" +) + +// MockMarshaler is a mock of Marshaler interface. +type MockMarshaler struct { + ctrl *gomock.Controller + recorder *MockMarshalerMockRecorder +} + +// MockMarshalerMockRecorder is the mock recorder for MockMarshaler. +type MockMarshalerMockRecorder struct { + mock *MockMarshaler +} + +// NewMockMarshaler creates a new mock instance. +func NewMockMarshaler(ctrl *gomock.Controller) *MockMarshaler { + mock := &MockMarshaler{ctrl: ctrl} + mock.recorder = &MockMarshalerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockMarshaler) EXPECT() *MockMarshalerMockRecorder { + return m.recorder +} + +// MarshallAccountsWithAvailableBalance mocks base method. +func (m *MockMarshaler) MarshallAccountsWithAvailableBalance(ctx context.Context, accounts []*account.Account) ([]*poolrpc.Account, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MarshallAccountsWithAvailableBalance", ctx, accounts) + ret0, _ := ret[0].([]*poolrpc.Account) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// MarshallAccountsWithAvailableBalance indicates an expected call of MarshallAccountsWithAvailableBalance. +func (mr *MockMarshalerMockRecorder) MarshallAccountsWithAvailableBalance(ctx, accounts interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarshallAccountsWithAvailableBalance", reflect.TypeOf((*MockMarshaler)(nil).MarshallAccountsWithAvailableBalance), ctx, accounts) +} diff --git a/rpcserver.go b/rpcserver.go index 67c7723..887f236 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -64,6 +64,7 @@ type rpcServer struct { auctioneer *auctioneer.Client accountManager account.Manager orderManager order.Manager + marshaler Marshaler quit chan struct{} wg sync.WaitGroup @@ -117,6 +118,10 @@ func newRPCServer(server *Server) *rpcServer { Wallet: lndServices.WalletKit, Signer: lndServices.Signer, }), + marshaler: NewMarshaler(&marshalerConfig{ + GetOrders: server.db.GetOrders, + Terms: server.AuctioneerClient.Terms, + }), quit: make(chan struct{}), } } @@ -589,7 +594,7 @@ func (s *rpcServer) ListAccounts(ctx context.Context, validAccounts = append(validAccounts, acct) } - rpcAccounts, err := s.MarshallAccountsWithAvailableBalance( + rpcAccounts, err := s.marshaler.MarshallAccountsWithAvailableBalance( ctx, validAccounts, ) if err != nil { @@ -602,77 +607,6 @@ func (s *rpcServer) ListAccounts(ctx context.Context, }, nil } -// MarshallAccountsWithAvailableBalance returns the RPC representation of an account -// with the account.AvailableBalance value populated. -func (s *rpcServer) 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 := s.server.db.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 := s.auctioneer.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 -} - // MarshallAccount returns the RPC representation of an account. func MarshallAccount(a *account.Account) (*poolrpc.Account, error) { var rpcState poolrpc.AccountState @@ -770,7 +704,7 @@ func (s *rpcServer) DepositAccount(ctx context.Context, return nil, err } - rpcModifiedAccounts, err := s.MarshallAccountsWithAvailableBalance( + rpcModAccounts, err := s.marshaler.MarshallAccountsWithAvailableBalance( ctx, []*account.Account{modifiedAccount}, ) if err != nil { @@ -779,7 +713,7 @@ func (s *rpcServer) DepositAccount(ctx context.Context, txHash := tx.TxHash() return &poolrpc.DepositAccountResponse{ - Account: rpcModifiedAccounts[0], + Account: rpcModAccounts[0], DepositTxid: txHash[:], }, nil } @@ -837,7 +771,7 @@ func (s *rpcServer) WithdrawAccount(ctx context.Context, return nil, err } - rpcModifiedAccounts, err := s.MarshallAccountsWithAvailableBalance( + rpcModAccounts, err := s.marshaler.MarshallAccountsWithAvailableBalance( ctx, []*account.Account{modifiedAccount}, ) if err != nil { @@ -846,7 +780,7 @@ func (s *rpcServer) WithdrawAccount(ctx context.Context, txHash := tx.TxHash() return &poolrpc.WithdrawAccountResponse{ - Account: rpcModifiedAccounts[0], + Account: rpcModAccounts[0], WithdrawTxid: txHash[:], }, nil } @@ -895,7 +829,7 @@ func (s *rpcServer) RenewAccount(ctx context.Context, return nil, err } - rpcModifiedAccounts, err := s.MarshallAccountsWithAvailableBalance( + rpcModAccounts, err := s.marshaler.MarshallAccountsWithAvailableBalance( ctx, []*account.Account{modifiedAccount}, ) if err != nil { @@ -904,7 +838,7 @@ func (s *rpcServer) RenewAccount(ctx context.Context, txHash := tx.TxHash() return &poolrpc.RenewAccountResponse{ - Account: rpcModifiedAccounts[0], + Account: rpcModAccounts[0], RenewalTxid: txHash[:], }, nil }