Skip to content

Commit

Permalink
Add two docs for full node & binary upgrade (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
TommyGarch committed Apr 2, 2024
1 parent f4ac263 commit 2665dcc
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 2 deletions.
6 changes: 4 additions & 2 deletions pages/guides/_meta.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"how_to_set_up_full_node": "How to set up a full node",
"how_to_uncross_orderbook": "How to uncross the orderbook",
"how_to_send_usdc_to_dydx": "How to send USDC from Ethereum to dYdX"
"how_to_send_usdc_to_dydx": "How to send USDC from Ethereum to dYdX",
"orderbook_stream": "Orderbook Stream",
"using_Cosmovisor_to_stage_dYdX_Chain": "Using Cosmovisor to Stage dYdX Chain"
}


160 changes: 160 additions & 0 deletions pages/guides/orderbook_stream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Orderbook Stream

This feature aims to provide real-time and accurate orderbook updates. Complete orderbook activities are streamed to the client and can be used to construct a full depth L3 orderbook. Streams are implemented using the existing GRPC query service from Cosmos SDK.

The initial implementation only contains orders but not trades. Also note that by dYdX V4’s design, the orderbook can be slightly different across different nodes.

## Enabling GRPC Streaming

This feature can be enabled via a command line flag (--grpc-streaming-enabled=true) when starting your full node. This feature can only be used on non validating full nodes and when grpc is also enabled.

## Request / Response

To subscribe to the stream, the client can send a 'StreamOrderbookUpdatesRequest' specifying the clob pair ids to subscribe to.

```go
// StreamOrderbookUpdatesRequest is a request message for the
// StreamOrderbookUpdates method.
message StreamOrderbookUpdatesRequest {
// Clob pair ids to stream orderbook updates for.
repeated uint32 clob_pair_id = 1;
}
```

Response will contain the orderbook updates (Add/Remove/Update), whether the updates are coming from a snapshot, and a few fields used for debugging issues.

```go
// StreamOrderbookUpdatesResponse is a response message for the
// StreamOrderbookUpdates method.
message StreamOrderbookUpdatesResponse {
// Orderbook updates for the clob pair.
repeated dydxprotocol.indexer.off_chain_updates.OffChainUpdateV1 updates = 1
[ (gogoproto.nullable) = false ];

// Snapshot indicates if the response is from a snapshot of the orderbook.
// This is true for the initial response and false for all subsequent updates.
// Note that if the snapshot is true, then all previous entries should be
// discarded and the orderbook should be resynced.
bool snapshot = 2;

// ---Additional fields used to debug issues---
// Block height of the updates.
uint32 block_height = 3;

// Exec mode of the updates.
uint32 exec_mode = 4;
}
```

## Example Scenario

- Trader places a bid at price 100 for size 1
- OrderPlace, price = 100, size = 1
- OrderUpdate, total filled amount = 0
- Trader replaces that original bid to be price 99 at size 2
- OrderRemove
- OrderPlace, price = 99, size = 2
- OrderUpdate, total filled amount = 0
- Another trader submits an IOC ask at price 100 for size 1.
- Full node doesn't see this matching anything so no updates.
- Block is confirmed that there was a fill for the trader's original order at price 100 for size 1 (BP didn't see the order replacement)
- OrderUpdate, total filled amount = 1


## Maintaining a local orderbook

Building a local orderbook should be fairly straight forward. Here is a quick [example PR](https://github.com/dydxprotocol/v4-chain/pull/1268) for a Go GRPC client that subscribes to the orderbook updates and maintains an orderbook locally.

Specifically after subscribing to the orderbook updates:

- Use the orderbook in the snapshot as the starting orderbook.
- Add the corresponding order to the end of the price level when `OrderPlaceV1` is received.

```go
func (l *LocalOrderbook) AddOrder(order v1types.IndexerOrder) {
l.Lock()
defer l.Unlock()

if _, ok := l.OrderIdToOrder[order.OrderId]; ok {
l.Logger.Error("order already exists in orderbook")
}

subticks := order.GetSubticks()
if order.Side == v1types.IndexerOrder_SIDE_BUY {
if _, ok := l.Bids[subticks]; !ok {
l.Bids[subticks] = make([]v1types.IndexerOrder, 0)
}
l.Bids[subticks] = append(l.Bids[subticks], order)
} else {
if _, ok := l.Asks[subticks]; !ok {
l.Asks[subticks] = make([]v1types.IndexerOrder, 0)
}
l.Asks[subticks] = append(l.Asks[subticks], order)
}

l.OrderIdToOrder[order.OrderId] = order
l.OrderRemainingAmount[order.OrderId] = 0
}
```

- Update the order remaining size when `OrderUpdateV1` is received

```go
func (l *LocalOrderbook) SetOrderRemainingAmount(orderId v1types.IndexerOrderId, totalFilledQuantums uint64) {
l.Lock()
defer l.Unlock()

order := l.OrderIdToOrder[orderId]
if totalFilledQuantums > order.Quantums {
l.Logger.Error("totalFilledQuantums > order.Quantums")
}
l.OrderRemainingAmount[orderId] = order.Quantums - totalFilledQuantums
}
```

- Remove the order from the orderbook when `OrderRemoveV1` is received.

```go
func (l *LocalOrderbook) RemoveOrder(orderId v1types.IndexerOrderId) {
l.Lock()
defer l.Unlock()

if _, ok := l.OrderIdToOrder[orderId]; !ok {
l.Logger.Error("order not found in orderbook")
}

order := l.OrderIdToOrder[orderId]
subticks := order.GetSubticks()

if order.Side == v1types.IndexerOrder_SIDE_BUY {
for i, o := range l.Bids[subticks] {
if o.OrderId == order.OrderId {
l.Bids[subticks] = append(
l.Bids[subticks][:i],
l.Bids[subticks][i+1:]...,
)
break
}
}
if len(l.Bids[subticks]) == 0 {
delete(l.Bids, subticks)
}
} else {
for i, o := range l.Asks[subticks] {
if o.OrderId == order.OrderId {
l.Asks[subticks] = append(
l.Asks[subticks][:i],
l.Asks[subticks][i+1:]...,
)
break
}
}
if len(l.Asks[subticks]) == 0 {
delete(l.Asks, subticks)
}
}

delete(l.OrderRemainingAmount, orderId)
delete(l.OrderIdToOrder, orderId)
}
```
39 changes: 39 additions & 0 deletions pages/guides/using_Cosmovisor_to_stage_dYdX_Chain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Using Cosmovisor to stage dYdX Chain binary upgrade

## Prerequisite

1. Linux (Ubuntu Server 22.04.3 recommended)
2. 8-cpu (ARM or x86_64), 64 GB RAM, 500 GB SSD NVME Storage
3. Already installed dYdXChain full node

## Preparation

1. Install Go from https://go.dev/doc/install (Version tested is 1.22.1)
2. Install Cosmovisor, with the following command:
go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@latest
3. Copy cosmovisor from $HOME/go/bin/ to a directory in your $PATH
4. Add two environment variables to $HOME/.profile. The data directory is typically $HOME/.dydx-mainnet-1
export DAEMON_NAME=dydxprotocold
export DAEMON_HOME=<your data directory>
5. Log out and log back in.
6. Initialize Cosmovisor with the following command. The <path to executable> is the the full path to dydxprotocold
cosmovisor init <path to executable>
7.Cosmovisor is now ready for use.

## Running dydxprotocold under Cosmovisor

You have to change the way you currently run dydxprotocold to run under Cosmovisor. This is done simply by specifying “cosmovisor run” in place of the “dydxprotocold” command you used previously. Therefore, if you previously used “dydxprotocold start --p2p.seeds="ade4d8…”, you would change that to “cosmovisor run start --p2p.seeds="ade4d8…”

## Staging upgrade

1. The Cosmovisor directory structure looks like this:

<img width="505" alt="Screenshot 2024-04-01 at 7 31 42 PM" src="https://github.com/TommyGarch/v4-documentation/assets/130097657/f7ed283f-4f6f-4ff6-8f73-490dc44c2388">

2. To stage an upgrade, you would create a <name> directory inside the upgrades/ directory. For example, as of 4/1/2024, the current version is v3.0.0 and the next upgrade version is v4.0.0. Therefore you would create a directory called “v4.0.0” and then a bin directory inside it.

<img width="700" alt="Screenshot 2024-04-01 at 7 32 11 PM" src="https://github.com/TommyGarch/v4-documentation/assets/130097657/62d68c4a-b081-4778-87b9-6fae206a8f9e">

3. Now, download the upgraded binary and put it inside the bin directory created previously. It must be named dydxprotocold

4. Restart dydxprotocold with Cosmovisor. Now, Cosmovisor will automatically halt the current binary at the block activation height and start the upgrade binary.

1 comment on commit 2665dcc

@vercel
Copy link

@vercel vercel bot commented on 2665dcc Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.