Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add streaming gRPC call to listen to orderbook events #123

Closed
sangaman opened this issue Jun 8, 2018 · 34 comments
Closed

Add streaming gRPC call to listen to orderbook events #123

sangaman opened this issue Jun 8, 2018 · 34 comments
Assignees
Labels
grpc gRPC API order book P1 top priority
Milestone

Comments

@sangaman
Copy link
Collaborator

sangaman commented Jun 8, 2018

This issue is about notifying clients when order book events occur such as an ownOrder being filled.

Events:

  1. ownOrder added success/error (placeOrder)
  2. ownOrder removed success/error (cancelOrder)
  3. ownOrder removed (due to internal match)
  4. ownOrder removed (due to a successful swap that was instantiated remotely)
  5. peerOrder added
  6. peerOrder removed (due to non-internal match and successful swap)
  7. peerOrder removed (due to peer order invalidation)
  8. peerOrder removed (due to swap failure)

placeOrder response covers (1), (3), and (6) (handled by #479)
placeOrderSync sync response covers (4), (8) (handled by #479)
cancelOrder response covers (2)
subscribeOrders covers (4), (5), (7), and (8)

placeOrder, is asynchronous and just returns an immediate success/error of placing an order. Swap results come in via subscribeOrders. There is a second placeOrderSync call which returns fail/success of a swap where we inform the client synchronously if the swap actually was successful or failed.

Note:
We already have (1) , (2), and (3) taken care of.

@moshababo
Copy link
Collaborator

We should clearly define the API after finalizing our descussions here.

In the meanwhile we should create a gRPC streaming call example. I'll open a separate issue for that.

@itsbalamurali
Copy link
Contributor

This also requires event emitter implementation on OrderBook and MatchingEngine beforehand and also predefining the events and their types.

@sangaman
Copy link
Collaborator Author

@moshababo I'd say we can make #128 be a very basic version of the orderbook subscription that this issue is for. Maybe start with a SubscribeOrders call that triggers an event whenever a peerOrder is received. I imagine we'll definitely want something like that and we can always tweak it later if necessary, plus it would be laying the groundwork for this issue. I'd be interested to get started on that soon.

@sangaman
Copy link
Collaborator Author

Although @itsbalamurali is right that we need to implement event emitters on the orderbook which has not been done yet, and perhaps that should be done separately from the streaming call example. Another possibility is a SubscribePeers call which triggers events when a new peer connects, since we already have some events set up on the p2p side of things.

@kilrau kilrau added this to the 1.0.0-alpha milestone Jun 19, 2018
@moshababo
Copy link
Collaborator

@sangaman yes, events are missing on the orderbook, and although we could easily add them, I think that the task should be focused on doing a technical POC with some dummy call, just so there won't be any other concerns.

@michael1011
Copy link
Contributor

Right now we have:

  • SubscribePeerOrders which takes care of new peer orders and cancellations of those.
  • SubscribeSwaps which should allow clients to subscribe to executed swaps.

This issue comes down to implementing SubscribeSwaps because SubscribePeerOrders does everything else?

@kilrau
Copy link
Contributor

kilrau commented Sep 5, 2018

At the moment 3 modes:

  1. Synchronous placeOrder call, non-internal match removes order immediately (problem)
  2. SubscribeSwaps - external match remove orders
  3. SubscribePeerOrders - remove invalidated peer orders

@kilrau
Copy link
Contributor

kilrau commented Sep 5, 2018

@michael1011 @moshababo @sangaman

Proposal: Combine all order updates into subscribeOrders

  • invalidates (local) OrderIDs: internal match, external match (after swap succeeded), invalidated peer orders, TBD: which additional info apart from orderID?
  • add new peer orders, TBD: which additional info apart from orderID?
  • Remove SubscribePeerOrders and SubscribeSwaps rpc calls

Known Problems:

  • ownOrder will show up e.g. in UI of exchange for some milliseconds, even though it got matched immediately in xud, because the stream event comes in with a bit of delay. Since this has no direct negative implications, I believe that's acceptable

@kilrau kilrau added the P1 top priority label Sep 5, 2018
@kilrau kilrau modified the milestones: 1.0.0-prealpha.3, 1.0.0-alpha Sep 5, 2018
@kilrau
Copy link
Contributor

kilrau commented Sep 5, 2018

Related: #298, #423

@moshababo
Copy link
Collaborator

To enable the client to sync with the order book state, we have 6 types of events:

  1. ownOrder added
  2. ownOrder removed (due to internal match)
  3. ownOrder removed (due to a succesful swap that was instantiated remotely)
  4. peerOrder added
  5. peerOrder removed (due to non-internal match)
  6. peerOrder removed (due to peer order invalidation)

Current API:

  • placeOrder response:
    • if remaining order exists, then it was added to the order book (ownOrder added (1)).
    • if internal match occurred, its maker order was removed (ownOrder removed (2)).
    • if non-internal match occurred, its maker order was removed (peerOrder removed (5)), and swap is instantiated. if it fails later, the maker order (peerOrder) won't be re-added, but we planned to retry matching the taker order (ownOrder). If so, and if the taker will not match, then it would be added to the order book, but there's no way to announce ownOrder added (1) to the client. This can be fixed by delegating the responsibility for re-matching to the client, after he heard that the the swap failed.
  • subscribePeerOrder stream: provides both peerOrder added (4) & peerOrder removed (6) events.

  • subscribeSwaps stream: if swap instantiated locally, it doesn't cover any event that placeOrder response doesn't. If instantiated remotely, and succeed, it provides the event ownOrder removed (3), which there is no other way to know about.

@sangaman @michael1011 @kilrau @offerm please verify that everything is correct.

Possible changes:

  • Keep placeOrder response the same.

  • Add subscribeOwnOrders to cover order removed (3), in addition to ownOrder added (1) + ownOrder removed (2) in an async manner. It will help putting all these together, and also to solve the problem of announcing ownOrder added (1) in case of no match after a failed swap.

  • Change subscribePeerOrder to cover peerOrder removed (5) in an async manner, in addition to the existing peerOrder added (4) + peerOrder removed (6).

  • Remove subscribeSwaps (at least for the sake of syncing with the order book state. it might be needed for other things)

It means that ownOrder removed (2) + peerOrder removed (5) could be both sync and async. Same for ownOrder added (1), if we don't try to rematch after a failed swap. if we do, it could be only async.

@kilrau
Copy link
Contributor

kilrau commented Sep 6, 2018

@sangaman @michael1011 @kilrau @offerm please verify that everything is correct.

Error event missing on placeOrder. Also ownOrder removed due to cancelOrder. Don't know what's common practice here - include a success/error code or separate event. Rest looks good.

  1. ownOrder added success/error (placeOrder)
  2. ownOrder removed success/error (cancelOrder)
  3. ownOrder removed (due to internal match)
  4. ownOrder removed (due to a successful swap that was instantiated remotely)
  5. peerOrder added
  6. peerOrder removed (due to non-internal match)
  7. peerOrder removed (due to peer order invalidation)

Possible changes:

I don't see any advantage in having separate calls subscribePeerOrders and subscribeOwnOrders. I suggest just two:

placeOrder: sync response (1)
cancelOrder: sync response (2)
subscribeOrders: streaming (3), (4), (5), (6), (7)

Next step: non-matching mode: #145
Other opinions? @sangaman @michael1011 @offerm @itsbalamurali

@sangaman
Copy link
Collaborator Author

Let's move persisting orders into a separate discussion.

I'd be very hesitant to hold on to orders that have been canceled or filled because we keep them in a priority queue, and having expired orders in there would complicate the matching process I believe. I can't think of any reason why we'd want them after they're completely filled or canceled, except possibly for historical purposes, but then we'd just persist to the db.

I think we've already agreed on 6, 7, and 8.

@offerm
Copy link
Contributor

offerm commented Sep 15, 2018

The point I'm trying to make is that this should be done with a list of a generice Event object without the discussion about how/when these Events are created.
Makes everything simple and not dependent on other components/logic.

My 2 cents.

@sangaman
Copy link
Collaborator Author

I was thinking about this some more, and I can think of 3 events that a client would be interested in hearing about:

  • A new peer order, for which the message will contain the order info.
  • An invalidated peer order, for which the message will contain the order identifier (orderId, pairId, quantity invalidated)
  • An executed own order, for which the message will contain orderId/pairId/quantity executed and possibly also pub key of the peer we swapped with, r_hash, or whatever else we figure is relevant. This can cover both maker and taker orders.

Since these seem like 3 distinct messages, I'm now leaning towards separate subscriptions for the separate events like @moshababo suggested earlier. I can probably come up with a PR with some code to discuss/review in the next couple of days.

@offerm
Copy link
Contributor

offerm commented Sep 16, 2018

So for every event that a user may want to hear we create a subscription RPC?

Also, why do you think a client would only be interested in these 3 events?

Better to develop a generic solution and allow the RPC user to filter event using regexp or similar solution.

@moshababo
Copy link
Collaborator

In regards to the list of events, and how they are triggered - this indeed can change tomorrow, but I thought it's a good idea to go through everything we have right now. It might affect our design decisions.

At the moment we see our order book state in terms of orders being Added and Removed (which includes Created, Cancelled & Split). What's missing is Swapped which we thought to handle separately. Keeping the non-active orders is not necessary for notifying state events. Once the order is Removed/Swapped, the event is notified, and the order instance is gone.

If we'll introduce Swapped as @offerm suggested, it will help solve the problem of expressing matches/swap results in terms of orders being added/removed from the order book, which obviously doesn't work well.

The other option is to continue to express Swapped as Removed, in addition to providing matches/swaps results which might contain different info.

Our current problems with it:

  • placeOrder response should return the matches, which also affect the order book state. Should we notify them anyway? Same for remainingOrder, which is also part of the response.
  • if placeOrder is async, where do we return the results? do we expose them only as order book state events? if placeOrder is sync, and we're aggregating the results, should we drop the async streaming events?

My suggestion:

  • We shouldn't mix matching results with the order book state events. When placeOrderSync is called, we'll aggregate the matches/swaps results (including remainingOrder), and stream the order book state events (Added / Removed) to subscribeOrders, in addition. (in contrary to what @kilrau suggested)
  • if placeOrder is called (async), we'll stream the exact same results back to it in async manner. This will make it very similar to placeOrderSync, and I think that's how sendPayment is implemented in LND.
  • on a successful maker swap (which wasn't triggered by placeOrder, but by a peer), we'll stream only order book state events (Removed).

That being said, the same problems exists also if we'll introduce the Swapped order state, as @offerm suggested. We need to decide if when placeOrderSync includes them, are they going to be streamed to subscribeOrders as well or not, and how are we going to implement async placeOrder.

@sangaman
Copy link
Collaborator Author

So for every event that a user may want to hear we create a subscription RPC?

I'd lean towards a separate subscription for each separate message type.

Also, why do you think a client would only be interested in these 3 events?

Those are the only three events (related to orders at least) that come to mind.

We shouldn't mix matching results with the order book state events. When placeOrderSync is called, we'll aggregate the matches/swaps results (including remainingOrder), and stream the order book state events (Added / Removed) to subscribeOrders, in addition. (in contrary to what @kilrau suggested)
if placeOrder is called (async), we'll stream the exact same results back to it in async manner. This will make it very similar to placeOrderSync, and I think that's how sendPayment is implemented in LND.
on a successful maker swap (which wasn't triggered by placeOrder, but by a peer), we'll stream only order book state events (Removed).

Sounds like a good approach!

@kilrau
Copy link
Contributor

kilrau commented Sep 18, 2018

This issue gets a little bit out of bounds. I updated the description with what we agreed before. Could you add a summary of the agreements on events? @offerm @moshababo @sangaman

We shouldn't mix matching results with the order book state events. When placeOrderSync is called, we'll aggregate the matches/swaps results (including remainingOrder), and stream the order book state events (Added / Removed) to subscribeOrders, in addition. (in contrary to what @kilrau suggested)
if placeOrder is called (async), we'll stream the exact same results back to it in async manner. This will make it very similar to placeOrderSync, and I think that's how sendPayment is implemented in LND.
on a successful maker swap (which wasn't triggered by placeOrder, but by a peer), we'll stream only order book state events (Removed).

Ok!

@kilrau
Copy link
Contributor

kilrau commented Sep 18, 2018

Discussion regarding placeOrderSync: #479

@moshababo
Copy link
Collaborator

I think we should do placeOrder / placeOrderSync separately, as part of #479.

This issue can be for the order book state events (Added, Removed), which we already specified. We can consider @offerm design suggestion, or keep our current approach.

Note on terminology: I tried to use different names for different contexts. I think we should keep Incoming / Invalidation events solely for the p2p context. From XUD to client we should use Added / Removed (past sentence), instead.

@michael1011 do you want to take this one?

The design need to take #145 into consideration.

@sangaman
Copy link
Collaborator Author

I've started some work on this actually, will open a PR soon and we can discuss some more there. I think it will be helpful to have some actual code as a reference.

@sangaman
Copy link
Collaborator Author

@moshababo Using "Removed" implies an order is being fully removed, but we have the possibility that the order is merely having its quantity reduced, for which "Invalidated" is slightly more clear. Maybe "Canceled"? It doesn't sound quite as absolute as "Removed" and I think it makes more sense to partly cancel an order than partly remove it. Thoughts?

sangaman added a commit that referenced this issue Sep 19, 2018
This commit replaces the old `subscribePeerOrders` and `subscribeSwaps`
rpc calls with three new streaming rpc calls:

- subscribeNewOrders: Notifies when new incoming peer orders are added.
- subscribeExpiredOrders: Notifies when peer orders become expired due
to being canceled or filled remotely.
- subscribeExecutedOrders: Notifies when local orders are executed via
a successful swap.

It also restructures and updates the `Order` grpc message type.

Closes #123.
@ghost ghost added in progress and removed to do labels Sep 19, 2018
@moshababo
Copy link
Collaborator

I don’t think it’s any less confusing to use “Invalidated” or “Cancelled” instead for this matter, nor that they are less absolute. We settled on solving this by defining the event payload as a tuple, orderId + quantity, so we’re always invalidating / removing a quantity.

I think the current terminology works well: Cancel is for API command (the opposite to placeOrder), “Invalidation” is for the p2p layer, and “Removed” is in the context of a local order book. IMO using these different names is appropriate and actually less confusing.

But I agree that the orderId + quantity tuple is a bit confusing. We can introduce another event for each context - PARTIAL_INVALIDATION, REMOVED_PARTIALLY \ SPLIT, which will make the existing events merely an alias for a full quantity case. I still prefer the current approach.

sangaman added a commit that referenced this issue Sep 26, 2018
This commit replaces the old `subscribePeerOrders` and `subscribeSwaps`
rpc calls with three new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
sangaman added a commit that referenced this issue Sep 26, 2018
This commit replaces the old `subscribePeerOrders` and `subscribeSwaps`
rpc calls with three new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
sangaman added a commit that referenced this issue Sep 26, 2018
This commit replaces the old `subscribePeerOrders` and `subscribeSwaps`
rpc calls with three new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
sangaman added a commit that referenced this issue Sep 27, 2018
This commit replaces the old streaming rpc subscription calls with three
new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
sangaman added a commit that referenced this issue Sep 27, 2018
This commit replaces the old streaming rpc subscription calls with three
new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
sangaman added a commit that referenced this issue Sep 28, 2018
This commit replaces the old streaming rpc subscription calls with three
new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
sangaman added a commit that referenced this issue Sep 29, 2018
This commit replaces the old streaming rpc subscription calls with three
new streaming rpc calls:

- subscribeAddedOrders: Notifies when orders are added to the order
book.
- subscribeRemovedOrders: Notifies when orders are removed from the
order book.
- subscribeSwaps: Notifies when swaps that are initiated by a remote
user are completed.

It also restructures and updates the `Order` grpc message type.

Closes #123.
@ghost ghost removed the in progress label Sep 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
grpc gRPC API order book P1 top priority
Projects
None yet
Development

No branches or pull requests

6 participants