add /debug to dlobPublisher
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -142,4 +142,8 @@ src/**.js.map
|
||||
lib
|
||||
src/playground.ts
|
||||
|
||||
*dump.rdb
|
||||
# redis files
|
||||
*.rdb
|
||||
*.log
|
||||
*.confg
|
||||
|
||||
|
||||
20
README.md
20
README.md
@@ -18,6 +18,12 @@ This is the backend server that provides a REST API for the drift [DLOB](https:/
|
||||
|
||||
## Setup
|
||||
|
||||
The build dependencies
|
||||
```
|
||||
git submodule update --init
|
||||
bash build_all.sh
|
||||
```
|
||||
|
||||
First set the necessary environment variables:
|
||||
```
|
||||
cp .env.example .env
|
||||
@@ -66,18 +72,28 @@ To run the websocket server, a Redis cache is required, and the following enviro
|
||||
* `REDIS_PASSWORDS`
|
||||
* `REDIS_PORTS`
|
||||
|
||||
In one terminal, run:
|
||||
In the first terminal, start the redis cluster:
|
||||
```
|
||||
bash redisCluster.sh start
|
||||
bash redisCluster.sh create
|
||||
```
|
||||
|
||||
In second terminal, run:
|
||||
```
|
||||
yarn run dlob-publisher
|
||||
```
|
||||
|
||||
In a second terminal, run:
|
||||
In a third terminal, run:
|
||||
```
|
||||
yarn run ws-manager
|
||||
```
|
||||
|
||||
Then connect to the ws server at ws://127.0.0.1:3000
|
||||
|
||||
When you're done, stop the redis cluster:
|
||||
```
|
||||
bash redisCluster.sh stop
|
||||
```
|
||||
|
||||
# Run the example client
|
||||
|
||||
|
||||
142
redisCluster.sh
Normal file
142
redisCluster.sh
Normal file
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
|
||||
# Settings
|
||||
CLUSTER_HOST=127.0.0.1
|
||||
PORT=6378
|
||||
TIMEOUT=2000
|
||||
NODES=6
|
||||
REPLICAS=1
|
||||
PROTECTED_MODE=yes
|
||||
ADDITIONAL_OPTIONS=""
|
||||
|
||||
# You may want to put the above config parameters into config.sh in order to
|
||||
# override the defaults without modifying this script.
|
||||
|
||||
if [ -a config.sh ]
|
||||
then
|
||||
source "config.sh"
|
||||
fi
|
||||
|
||||
# Computed vars
|
||||
ENDPORT=$((PORT+NODES))
|
||||
|
||||
if [ "$1" == "start" ]
|
||||
then
|
||||
while [ $((PORT < ENDPORT)) != "0" ]; do
|
||||
PORT=$((PORT+1))
|
||||
echo "Starting $PORT"
|
||||
redis-server --port $PORT --protected-mode $PROTECTED_MODE --cluster-enabled yes --cluster-config-file nodes-${PORT}.conf --cluster-node-timeout $TIMEOUT --appendonly yes --appendfilename appendonly-${PORT}.aof --appenddirname appendonlydir-${PORT} --dbfilename dump-${PORT}.rdb --logfile ${PORT}.log --daemonize yes ${ADDITIONAL_OPTIONS}
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "create" ]
|
||||
then
|
||||
HOSTS=""
|
||||
while [ $((PORT < ENDPORT)) != "0" ]; do
|
||||
PORT=$((PORT+1))
|
||||
HOSTS="$HOSTS $CLUSTER_HOST:$PORT"
|
||||
done
|
||||
OPT_ARG=""
|
||||
if [ "$2" == "-f" ]; then
|
||||
OPT_ARG="--cluster-yes"
|
||||
fi
|
||||
redis-cli --cluster create $HOSTS --cluster-replicas $REPLICAS $OPT_ARG
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "stop" ]
|
||||
then
|
||||
while [ $((PORT < ENDPORT)) != "0" ]; do
|
||||
PORT=$((PORT+1))
|
||||
echo "Stopping $PORT"
|
||||
redis-cli -p $PORT shutdown nosave
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "restart" ]
|
||||
then
|
||||
OLD_PORT=$PORT
|
||||
while [ $((PORT < ENDPORT)) != "0" ]; do
|
||||
PORT=$((PORT+1))
|
||||
echo "Stopping $PORT"
|
||||
redis-cli -p $PORT shutdown nosave
|
||||
done
|
||||
PORT=$OLD_PORT
|
||||
while [ $((PORT < ENDPORT)) != "0" ]; do
|
||||
PORT=$((PORT+1))
|
||||
echo "Starting $PORT"
|
||||
redis-server --port $PORT --protected-mode $PROTECTED_MODE --cluster-enabled yes --cluster-config-file nodes-${PORT}.conf --cluster-node-timeout $TIMEOUT --appendonly yes --appendfilename appendonly-${PORT}.aof --appenddirname appendonlydir-${PORT} --dbfilename dump-${PORT}.rdb --logfile ${PORT}.log --daemonize yes ${ADDITIONAL_OPTIONS}
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "watch" ]
|
||||
then
|
||||
PORT=$((PORT+1))
|
||||
while [ 1 ]; do
|
||||
clear
|
||||
date
|
||||
redis-cli -p $PORT cluster nodes | head -30
|
||||
sleep 1
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "tail" ]
|
||||
then
|
||||
INSTANCE=$2
|
||||
PORT=$((PORT+INSTANCE))
|
||||
tail -f ${PORT}.log
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "tailall" ]
|
||||
then
|
||||
tail -f *.log
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "call" ]
|
||||
then
|
||||
while [ $((PORT < ENDPORT)) != "0" ]; do
|
||||
PORT=$((PORT+1))
|
||||
redis-cli -p $PORT $2 $3 $4 $5 $6 $7 $8 $9
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "clean" ]
|
||||
then
|
||||
echo "Cleaning *.log"
|
||||
rm -rf *.log
|
||||
echo "Cleaning appendonlydir-*"
|
||||
rm -rf appendonlydir-*
|
||||
echo "Cleaning dump-*.rdb"
|
||||
rm -rf dump-*.rdb
|
||||
echo "Cleaning nodes-*.conf"
|
||||
rm -rf nodes-*.conf
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" == "clean-logs" ]
|
||||
then
|
||||
echo "Cleaning *.log"
|
||||
rm -rf *.log
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Usage: $0 [start|create|stop|restart|watch|tail|tailall|clean|clean-logs|call]"
|
||||
echo "start -- Launch Redis Cluster instances."
|
||||
echo "create [-f] -- Create a cluster using redis-cli --cluster create."
|
||||
echo "stop -- Stop Redis Cluster instances."
|
||||
echo "restart -- Restart Redis Cluster instances."
|
||||
echo "watch -- Show CLUSTER NODES output (first 30 lines) of first node."
|
||||
echo "tail <id> -- Run tail -f of instance at base port + ID."
|
||||
echo "tailall -- Run tail -f for all the log files at once."
|
||||
echo "clean -- Remove all instances data, logs, configs."
|
||||
echo "clean-logs -- Remove just instances logs."
|
||||
echo "call <cmd> -- Call a command (up to 7 arguments) on all nodes."
|
||||
@@ -247,7 +247,7 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
|
||||
l2Formatted['marketSlot'] !== lastMarketSlotAndTime.slot
|
||||
) {
|
||||
logger.warn(
|
||||
`Updating market slot for ${marketArgs.marketName} with slot ${l2Formatted['marketSlot']}`
|
||||
`Updating market slot for ${marketArgs.marketName} from ${lastMarketSlotAndTime.slot} -> ${l2Formatted['marketSlot']}`
|
||||
);
|
||||
this.lastMarketSlotMap
|
||||
.get(marketArgs.marketType)
|
||||
@@ -262,6 +262,13 @@ export class DLOBSubscriberIO extends DLOBSubscriber {
|
||||
asks: l2Formatted.asks.slice(0, 100),
|
||||
});
|
||||
|
||||
console.log(
|
||||
`bbo: ${l2Formatted['marketName']}`,
|
||||
(+l2Formatted.bids[0].price / 1e6).toFixed(4),
|
||||
'//',
|
||||
(+l2Formatted.asks[0].price / 1e6).toFixed(4)
|
||||
);
|
||||
|
||||
this.redisClient.publish(
|
||||
`${clientPrefix}orderbook_${marketType}_${marketArgs.marketIndex}`,
|
||||
l2Formatted
|
||||
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
PerpMarketConfig,
|
||||
SpotMarketConfig,
|
||||
PhoenixSubscriber,
|
||||
MarketType,
|
||||
OraclePriceData,
|
||||
} from '@drift-labs/sdk';
|
||||
import { RedisClient, RedisClientPrefix } from '@drift/common/clients';
|
||||
|
||||
@@ -25,6 +27,7 @@ import { logger, setLogLevel } from '../utils/logger';
|
||||
import {
|
||||
SubscriberLookup,
|
||||
getOpenbookSubscriber,
|
||||
l2WithBNToStrings,
|
||||
parsePositiveIntArray,
|
||||
sleep,
|
||||
} from '../utils/utils';
|
||||
@@ -40,7 +43,7 @@ import {
|
||||
} from '../dlobProvider';
|
||||
import FEATURE_FLAGS from '../utils/featureFlags';
|
||||
import { GeyserOrderSubscriber } from '../grpc/OrderSubscriberGRPC';
|
||||
import express from 'express';
|
||||
import express, { Response, Request } from 'express';
|
||||
import { handleHealthCheck } from '../core/metrics';
|
||||
import { setGlobalDispatcher, Agent } from 'undici';
|
||||
|
||||
@@ -453,6 +456,50 @@ const main = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleDebug = async (req: Request, res: Response) => {
|
||||
const marketIndex = +req.query.marketIndex;
|
||||
let marketType: MarketType = MarketType.PERP;
|
||||
let oraclePriceData: OraclePriceData;
|
||||
if (req.query.marketType === 'spot') {
|
||||
marketType = MarketType.SPOT;
|
||||
oraclePriceData = driftClient.getOracleDataForSpotMarket(marketIndex);
|
||||
} else {
|
||||
oraclePriceData = driftClient.getOracleDataForPerpMarket(marketIndex);
|
||||
}
|
||||
try {
|
||||
const slot = slotSource.getSlot();
|
||||
const dlob = await dlobProvider.getDLOB(slot);
|
||||
const l2 = dlob.getL2({
|
||||
marketIndex,
|
||||
marketType,
|
||||
depth: 5,
|
||||
slot,
|
||||
oraclePriceData,
|
||||
});
|
||||
const l3 = dlob.getL3({
|
||||
marketIndex,
|
||||
marketType,
|
||||
slot,
|
||||
oraclePriceData,
|
||||
});
|
||||
const state = {
|
||||
dlobSize: dlobProvider.size(),
|
||||
slot,
|
||||
markets: {
|
||||
perp: perpMarketInfos,
|
||||
spot: spotMarketInfos,
|
||||
},
|
||||
l2: l2WithBNToStrings(l2),
|
||||
l3,
|
||||
};
|
||||
|
||||
res.json(state);
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: e.message });
|
||||
}
|
||||
};
|
||||
app.get('/debug', handleDebug);
|
||||
|
||||
app.get(
|
||||
'/health',
|
||||
handleHealthCheck(WS_FALLBACK_FETCH_INTERVAL, dlobProvider)
|
||||
|
||||
@@ -37,6 +37,21 @@ export const l2WithBNToStrings = (l2: L2OrderBook): any => {
|
||||
return l2;
|
||||
};
|
||||
|
||||
export const l3WithBNToStrings = (l3: L3OrderBook): any => {
|
||||
for (const key of Object.keys(l3)) {
|
||||
for (const idx in l3[key]) {
|
||||
const level = l3[key][idx];
|
||||
l3[key][idx] = {
|
||||
price: level.price.toString(),
|
||||
size: level.size.toString(),
|
||||
maker: level.maker.toBase58(),
|
||||
orderId: level.orderId.toString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
return l3;
|
||||
};
|
||||
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
16
yarn.lock
16
yarn.lock
@@ -460,11 +460,12 @@
|
||||
kuler "^2.0.0"
|
||||
|
||||
"@drift-labs/sdk@file:./drift-common/protocol/sdk", "@drift-labs/sdk@file:drift-common/protocol/sdk":
|
||||
version "2.96.0-beta.25"
|
||||
version "2.103.0-beta.8"
|
||||
dependencies:
|
||||
"@coral-xyz/anchor" "0.28.0"
|
||||
"@coral-xyz/anchor-30" "npm:@coral-xyz/anchor@0.30.1"
|
||||
"@ellipsis-labs/phoenix-sdk" "^1.4.2"
|
||||
"@grpc/grpc-js" "^1.8.0"
|
||||
"@openbook-dex/openbook-v2" "0.2.10"
|
||||
"@project-serum/serum" "^0.13.38"
|
||||
"@pythnetwork/client" "2.5.3"
|
||||
@@ -473,18 +474,20 @@
|
||||
"@solana/spl-token" "0.3.7"
|
||||
"@solana/web3.js" "1.92.3"
|
||||
"@switchboard-xyz/on-demand" "1.2.42"
|
||||
"@triton-one/yellowstone-grpc" "0.6.0"
|
||||
anchor-bankrun "^0.3.0"
|
||||
node-cache "^5.1.2"
|
||||
rpc-websockets "7.5.1"
|
||||
solana-bankrun "^0.3.0"
|
||||
strict-event-emitter-types "^2.0.0"
|
||||
tweetnacl "1.0.3"
|
||||
uuid "^8.3.2"
|
||||
zstddec "^0.1.0"
|
||||
|
||||
"@drift/common@file:./drift-common/common-ts":
|
||||
version "1.0.0"
|
||||
dependencies:
|
||||
"@drift-labs/sdk" "file:../../Library/Caches/Yarn/v6/npm-@drift-common-1.0.0-79940387-1595-4bdc-b73c-2bd48440a03a-1729802406625/node_modules/@drift/protocol/sdk"
|
||||
"@drift-labs/sdk" "file:../../Library/Caches/Yarn/v6/npm-@drift-common-1.0.0-2478b7b0-73c2-48c2-8cdc-077c34db7294-1733168269147/node_modules/@drift/protocol/sdk"
|
||||
"@jest/globals" "^29.3.1"
|
||||
"@slack/web-api" "^6.4.0"
|
||||
"@solana/spl-token" "^0.3.8"
|
||||
@@ -2140,6 +2143,13 @@
|
||||
js-yaml "^4.1.0"
|
||||
protobufjs "^7.2.6"
|
||||
|
||||
"@triton-one/yellowstone-grpc@0.6.0":
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@triton-one/yellowstone-grpc/-/yellowstone-grpc-0.6.0.tgz#9e6376cec8a42284c23dc195df2c3423c87c4f27"
|
||||
integrity sha512-rgdZM2N3U9/d/QKOI5PP+9rSHUl2oSI5Uwzvuss8y/mtTaHFjbOMpXpQXviIeDkusOa+mef4wLYrbjEZCwTXiw==
|
||||
dependencies:
|
||||
"@grpc/grpc-js" "^1.8.0"
|
||||
|
||||
"@triton-one/yellowstone-grpc@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@triton-one/yellowstone-grpc/-/yellowstone-grpc-0.3.0.tgz#2318b98b9ee80871e4ee8f9259f3d8673bf2c576"
|
||||
@@ -6307,7 +6317,7 @@ tsutils@^3.21.0:
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
tweetnacl@^1.0.3:
|
||||
tweetnacl@1.0.3, tweetnacl@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
|
||||
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
|
||||
|
||||
Reference in New Issue
Block a user