diff --git a/client/core/core.go b/client/core/core.go index a2b476bae5..ee54674c3a 100644 --- a/client/core/core.go +++ b/client/core/core.go @@ -60,6 +60,9 @@ type dexConnection struct { tradeMtx sync.RWMutex trades map[order.OrderID]*trackedTrade + + suspensionEpochMtx sync.RWMutex + suspensionEpoch uint64 } // refreshMarkets rebuilds, saves, and returns the market map. The map itself @@ -1085,6 +1088,22 @@ func (c *Core) Trade(pw string, form *TradeForm) (*Order, error) { return nil, fmt.Errorf("unknown DEX %s", form.DEX) } + // Avoid placing an order if the dexConnection is scheduled for a + // trade suspension. + // + // TODO: This needs further refinement, it's possible trades can be made + // after the suspension message is received if it starts minutes, hours or + // days into the future. we'll need to ensure the trades being made are + // handled in an epoch less than the starting epoch time for the trade + // suspension. + dc.suspensionEpochMtx.RLock() + scheduledSuspension := dc.suspensionEpoch != 0 + dc.suspensionEpochMtx.RUnlock() + if scheduledSuspension { + return nil, fmt.Errorf("order placement suspended due to impending"+ + " trade suspension for dex %s", dc.acct.url) + } + rate, qty := form.Rate, form.Qty if form.IsLimit && rate == 0 { return nil, fmt.Errorf("zero-rate order not allowed") @@ -1918,6 +1937,21 @@ func handleMatchProofMsg(_ *Core, dc *dexConnection, msg *msgjson.Message) error return ob.ValidateMatchProof(note) } +// handleTradeSuspensionMsg is called when a trade_suspension message is received. +func handleTradeSuspensionMsg(_ *Core, dc *dexConnection, msg *msgjson.Message) error { + var suspension msgjson.TradeSuspensionRequest + err := msg.Unmarshal(&suspension) + if err != nil { + return fmt.Errorf("trade suspenion unmarshal error: %v", err) + } + + dc.suspensionEpochMtx.Lock() + dc.suspensionEpoch = suspension.Epoch + dc.suspensionEpochMtx.Unlock() + + return nil +} + // routeHandler is a handler for a message from the DEX. type routeHandler func(*Core, *dexConnection, *msgjson.Message) error @@ -1928,7 +1962,7 @@ var reqHandlers = map[string]routeHandler{ msgjson.AuditRoute: handleAuditRoute, msgjson.RedemptionRoute: handleRedemptionRoute, msgjson.RevokeMatchRoute: nil, - msgjson.SuspensionRoute: nil, + msgjson.SuspensionRoute: handleTradeSuspensionMsg, } var noteHandlers = map[string]routeHandler{ diff --git a/dex/msgjson/types.go b/dex/msgjson/types.go index eedf5ea0aa..a6a5a123ac 100644 --- a/dex/msgjson/types.go +++ b/dex/msgjson/types.go @@ -689,6 +689,12 @@ type PreimageRequest struct { CommitChecksum Bytes `json:"csum"` } +// TradeSuspensionRequest is the server-origination trade suspension payload. +type TradeSuspensionRequest struct { + Epoch uint64 `json:"epoch"` + Persist bool `json:"persist"` +} + // PreimageResponse is the client-originating preimage response payload. type PreimageResponse struct { Preimage Bytes `json:"pimg"`