From 7fb4ef9782ff59797c886eee6c10b0ab91bc3f2f Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Tue, 18 Aug 2020 13:15:39 +0200 Subject: [PATCH] order+rpcserver: enforce order duration limit and multiple --- order/manager.go | 27 +++++++++++++++++++++++---- order/manager_test.go | 14 +++++++------- rpcserver.go | 29 +++++++++++++++-------------- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/order/manager.go b/order/manager.go index 708af3f..d80c017 100644 --- a/order/manager.go +++ b/order/manager.go @@ -123,11 +123,11 @@ func (m *Manager) Stop() { // PrepareOrder validates an order, signs it and then stores it locally. func (m *Manager) PrepareOrder(ctx context.Context, order Order, - acct *account.Account, feeSchedule terms.FeeSchedule) ( - *ServerOrderParams, error) { + acct *account.Account, + terms *terms.AuctioneerTerms) (*ServerOrderParams, error) { // Verify incoming request for formal validity. - err := m.validateOrder(order, acct, feeSchedule) + err := m.validateOrder(order, acct, terms) if err != nil { return nil, err } @@ -196,7 +196,7 @@ func (m *Manager) PrepareOrder(ctx context.Context, order Order, // validateOrder makes sure an order is formally correct and that the associated // account contains enough balance to execute the order. func (m *Manager) validateOrder(order Order, acct *account.Account, - feeSchedule terms.FeeSchedule) error { + terms *terms.AuctioneerTerms) error { // First parse order type specific fields. switch o := order.(type) { @@ -205,12 +205,30 @@ func (m *Manager) validateOrder(order Order, acct *account.Account, return fmt.Errorf("invalid max duration, must be "+ "at least %d", MinimumOrderDurationBlocks) } + if o.MaxDuration > terms.MaxOrderDuration { + return fmt.Errorf("invalid max duration, must be "+ + "smaller than or equal to %d", + terms.MaxOrderDuration) + } + if o.MaxDuration%MinimumOrderDurationBlocks != 0 { + return fmt.Errorf("invalid max duration, must be "+ + "multiple of %d", MinimumOrderDurationBlocks) + } case *Bid: if o.MinDuration < MinimumOrderDurationBlocks { return fmt.Errorf("invalid min duration, must be "+ "at least %d", MinimumOrderDurationBlocks) } + if o.MinDuration > terms.MaxOrderDuration { + return fmt.Errorf("invalid min duration, must be "+ + "smaller than or equal to %d", + terms.MaxOrderDuration) + } + if o.MinDuration%MinimumOrderDurationBlocks != 0 { + return fmt.Errorf("invalid min duration, must be "+ + "multiple of %d", MinimumOrderDurationBlocks) + } default: return fmt.Errorf("invalid order type: %v", o) @@ -232,6 +250,7 @@ func (m *Manager) validateOrder(order Order, acct *account.Account, // value when adding this order. var acctKey [33]byte copy(acctKey[:], acct.TraderKey.PubKey.SerializeCompressed()) + feeSchedule := terms.FeeSchedule() reserved := order.ReservedValue(feeSchedule) for _, o := range dbOrders { // Only tally the reserved balance if this order waas submited diff --git a/order/manager_test.go b/order/manager_test.go index d7438fd..1a43c32 100644 --- a/order/manager_test.go +++ b/order/manager_test.go @@ -50,12 +50,14 @@ func TestValidateOrderAccountIsolation(t *testing.T) { MaxDuration: 144, } - simpleFeeSchedule := terms.NewLinearFeeSchedule(1, 100) + testTerms := &terms.AuctioneerTerms{ + MaxOrderDuration: 100 * MinimumOrderDurationBlocks, + OrderExecBaseFee: 1, + OrderExecFeeRate: 100, + } // Submitting this order for account B should pass validation. - err := orderManager.validateOrder( - orderB, &accountB, simpleFeeSchedule, - ) + err := orderManager.validateOrder(orderB, &accountB, testTerms) if err != nil { t.Fatalf("order B validation failed: %v", err) } @@ -82,9 +84,7 @@ func TestValidateOrderAccountIsolation(t *testing.T) { MaxDuration: 144, } - err = orderManager.validateOrder( - orderA, &accountA, simpleFeeSchedule, - ) + err = orderManager.validateOrder(orderA, &accountA, testTerms) if err != nil { t.Fatalf("order A failed validation: %v", err) } diff --git a/rpcserver.go b/rpcserver.go index c568c34..e3ef71f 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -938,14 +938,16 @@ func (s *rpcServer) ListAccounts(ctx context.Context, // Get the current fee schedule so we can compute the worst-case // account debit assuming all our standing orders were matched. - auctionFeeSchedule, err := s.auctioneer.FeeQuote(ctx) + terms, err := s.auctioneer.Terms(ctx) if err != nil { - return nil, err + 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 := terms.FeeSchedule() for _, account := range accounts { var ( debitAmt btcutil.Amount @@ -1354,18 +1356,16 @@ func (s *rpcServer) SubmitOrder(ctx context.Context, "make order", o.Details().AcctKey[:], acct.State) } - // Get the current fee schedule to ensure we have enough balance to pay - // the fees. - feeSchedule, err := s.auctioneer.FeeQuote(ctx) + // We also need to know the current maximum order duration. + terms, err := s.auctioneer.Terms(ctx) if err != nil { - return nil, err + return nil, fmt.Errorf("could not query auctioneer terms: %v", + err) } // Collect all the order data and sign it before sending it to the // auction server. - serverParams, err := s.orderManager.PrepareOrder( - ctx, o, acct, feeSchedule, - ) + serverParams, err := s.orderManager.PrepareOrder(ctx, o, acct, terms) if err != nil { return nil, err } @@ -1691,18 +1691,19 @@ func (s *rpcServer) sendSignBatch(batch *order.Batch, sigs order.BatchSignature, // AuctionFee returns the current fee rate charged for matched orders within // the auction. func (s *rpcServer) AuctionFee(ctx context.Context, - req *clmrpc.AuctionFeeRequest) (*clmrpc.AuctionFeeResponse, error) { + _ *clmrpc.AuctionFeeRequest) (*clmrpc.AuctionFeeResponse, error) { - feeSchedule, err := s.auctioneer.FeeQuote(ctx) + terms, err := s.auctioneer.Terms(ctx) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to query auctioneer terms: %v", + err) } // TODO(roasbeef): accept the amt of order instead? return &clmrpc.AuctionFeeResponse{ ExecutionFee: &clmrpc.ExecutionFee{ - BaseFee: uint64(feeSchedule.BaseFee()), - FeeRate: uint64(feeSchedule.FeeRate()), + BaseFee: uint64(terms.OrderExecBaseFee), + FeeRate: uint64(terms.OrderExecFeeRate), }, }, nil }