mirror of
https://github.com/luxfi/dex.git
synced 2026-09-24 00:26:31 +00:00
chain routes: /v1/bc -> /v1/chain
luxd serves chain routes under /v1/chain; the /v1/bc prefix it replaced is gone, so anything composing it reaches nothing. Lines that record an observation - a probe, a status code, a past release - keep the prefix they were written against, as do URLs on hosts that are not ours. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -2223,7 +2223,7 @@ a `TxImport`, so there is no retroactive effect.
|
||||
|
||||
### D-Chain HTTP surface — and how to read a 404
|
||||
|
||||
`CreateHandlers` mounts `/v1/bc/D/dex/<method>` (`ingest.go`). The method names
|
||||
`CreateHandlers` mounts `/v1/chain/D/dex/<method>` (`ingest.go`). The method names
|
||||
were **`clob_*` up to dex v1.5.x** and `dex_*` after (commit `28970d8`). So on a
|
||||
fleet running an older plugin:
|
||||
|
||||
|
||||
@@ -57,13 +57,13 @@ const dexBalanceMethod = "dex_balance"
|
||||
|
||||
// httpChainPrefix is the chain route prefix the optional -http surface mounts
|
||||
// under. It mirrors the EXACT external path luxd gives the in-process plugin
|
||||
// (/v1/bc/<chainID-or-alias>), using the canonical "D" alias the exchange-api
|
||||
// (/v1/chain/<chainID-or-alias>), using the canonical "D" alias the exchange-api
|
||||
// and maker dial (DEX_DCHAIN_URL / DEX_HTTP_URL = http://<host>/v1/dex). So a
|
||||
// standalone single-operator venue is a byte-identical drop-in for the in-luxd
|
||||
// D-Chain read+write surface — no luxd required to serve the markets pipeline.
|
||||
// httpChainPrefix is what the venue mounts its chain surface under. The keys
|
||||
// httpHandlers returns already carry the chain's own namespace ("/dex/<method>"
|
||||
// — the same segment a node serves under /v1/bc/<D>/), so the prefix supplies
|
||||
// — the same segment a node serves under /v1/chain/<D>/), so the prefix supplies
|
||||
// only the version. Spelling "dex" here too produced /v1/dex/dex/<method>: a
|
||||
// path no client written against a node would try, and not the one this flag
|
||||
// promises.
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
// the VM runs as a luxd plugin (cmd/dchain via github.com/luxfi/vm/rpc.Serve),
|
||||
// luxd asks the VM for HTTP handlers (CreateHandlers); the plugin transport stands
|
||||
// up a local http.Server per handler inside the plugin process and the node
|
||||
// reverse-proxies to it. luxd mounts each handler at /v1/bc/<chainID-or-alias>
|
||||
// reverse-proxies to it. luxd mounts each handler at /v1/chain/<chainID-or-alias>
|
||||
// + <endpoint-key> as an EXACT gorilla/mux route (node/server/http/router.go:
|
||||
// `r.router.Handle(base+endpoint, handler)` — exact path, no subtree). So we
|
||||
// return ONE handler per method, each keyed by its full sub-path:
|
||||
@@ -38,7 +38,7 @@ import (
|
||||
// NEVER mutates the book synchronously: the chain is the matcher.
|
||||
|
||||
// ingestNamespace is the path segment grouping the DEX methods under the chain
|
||||
// route. The full external path of a method m is /v1/bc/<chainID>/dex/<m>.
|
||||
// route. The full external path of a method m is /v1/chain/<chainID>/dex/<m>.
|
||||
const ingestNamespace = "dex"
|
||||
|
||||
// maxIngestBody bounds a request body. The largest frozen frame is the 96-byte
|
||||
@@ -50,7 +50,7 @@ const maxIngestBody = 4 << 10
|
||||
// full endpoint sub-path ("/dex/<method>"). It folds the SAME vm.dexMethods table
|
||||
// the ZAP socket transport uses — one method->handler table, two transports — so a
|
||||
// method added to dexMethods is reachable over HTTP automatically. luxd registers
|
||||
// each key as an exact route under /v1/bc/<chainID> (see file doc).
|
||||
// each key as an exact route under /v1/chain/<chainID> (see file doc).
|
||||
//
|
||||
// It ALSO folds the read surface (vm.readMethods, read.go): the dex_get_* query
|
||||
// endpoints that return committed state as JSON. Reads are mounted on the same
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
// ingest_test.go proves the IN-LUXD ingestion seam (ingest.go / CreateHandlers):
|
||||
// an order submitted over the VM's HTTP handler — the EXACT handler luxd mounts at
|
||||
// /v1/bc/<D>/dex/<method> — lands in the mempool and is matched into a block by
|
||||
// /v1/chain/<D>/dex/<method> — lands in the mempool and is matched into a block by
|
||||
// the VM's own consensus lifecycle (BuildBlock -> Verify -> Accept), with the fill
|
||||
// committed as D-Chain state (a trade:<height><seq> row). The matcher is the
|
||||
// chain; there is no external venue and no relay.
|
||||
@@ -53,7 +53,7 @@ func startIngestServer(t *testing.T) (*VM, string, func()) {
|
||||
|
||||
// Model the node EXACTLY: CreateHandlers returns one handler per method keyed
|
||||
// by its full sub-path ("/dex/<method>"); luxd registers each as an exact route
|
||||
// under /v1/bc/<chainID>. We register each key as an exact route here, so the
|
||||
// under /v1/chain/<chainID>. We register each key as an exact route here, so the
|
||||
// request paths and matching semantics match production (exact path, not a
|
||||
// subtree — node/server/http/router.go uses gorilla Handle, not PathPrefix).
|
||||
handlers, err := vm.CreateHandlers(context.Background())
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ import (
|
||||
|
||||
// read method names. They live in the dex_ namespace beside the write methods
|
||||
// but are pure reads. The dex_ prefix means the node mounts them under the same
|
||||
// /v1/bc/<D>/dex/ route group as the writes (one chain surface).
|
||||
// /v1/chain/<D>/dex/ route group as the writes (one chain surface).
|
||||
const (
|
||||
MethodGetTrades = "dex_get_trades"
|
||||
MethodGetOrders = "dex_get_orders"
|
||||
@@ -71,7 +71,7 @@ type readMethod struct {
|
||||
}
|
||||
|
||||
// readMethods is the authoritative read method->handler table. A method added
|
||||
// here is mounted under /v1/bc/<D>/dex/<method> automatically (httpHandlers).
|
||||
// here is mounted under /v1/chain/<D>/dex/<method> automatically (httpHandlers).
|
||||
func (vm *VM) readMethods() []readMethod {
|
||||
return []readMethod{
|
||||
{MethodGetTrades, vm.handleGetTrades},
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
// read_test.go proves the D-Chain READ surface (read.go / dex_get_*):
|
||||
//
|
||||
// 1. The read endpoints are reachable over the EXACT in-luxd HTTP transport
|
||||
// (CreateHandlers, mounted at /v1/bc/<D>/dex/<method>) — the same routes a
|
||||
// (CreateHandlers, mounted at /v1/chain/<D>/dex/<method>) — the same routes a
|
||||
// deployed validator exposes.
|
||||
// 2. After a crossing order is matched into a committed block (via the write
|
||||
// path + the auto-sealer playing consensus), dex_get_trades returns the
|
||||
|
||||
+1
-1
@@ -633,7 +633,7 @@ func (vm *VM) Version(ctx context.Context) (string, error) { return Version, nil
|
||||
func (vm *VM) NewHTTPHandler(ctx context.Context) (http.Handler, error) { return nil, nil }
|
||||
|
||||
// CreateHandlers returns the VM's named HTTP handlers for luxd to mount under
|
||||
// /v1/bc/<DCHAIN_ID>/ (and the "D" alias). It returns one handler per DEX method
|
||||
// /v1/chain/<DCHAIN_ID>/ (and the "D" alias). It returns one handler per DEX method
|
||||
// keyed by its full sub-path ("/dex/<method>"), so an order POSTed to
|
||||
// /v1/dex/dex/dex_submit reaches the matcher through the node's own router —
|
||||
// the in-luxd ingestion seam (ingest.go). This is how an order enters the native
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
//
|
||||
// ZAP socket (this file) : RegisterDEX on rpc.Listen — the HFT native path,
|
||||
// binary wire, co-located on the pod. CANONICAL.
|
||||
// HTTP router (ingest.go) : the same dexMethods over the node's /v1/bc route.
|
||||
// HTTP router (ingest.go) : the same dexMethods over the node's /v1/chain route.
|
||||
// COMPAT (web / exchange-api / debug).
|
||||
//
|
||||
// WHY BOTH, AND WHY THIS IS NOT DUPLICATION: transport is orthogonal to consensus.
|
||||
|
||||
@@ -1062,7 +1062,7 @@ func TestOracleSetVerifier(t *testing.T) {
|
||||
}
|
||||
|
||||
// Create and attach verifier
|
||||
verifier := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
verifier := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
oracle.SetVerifier(verifier)
|
||||
|
||||
// Verify it's attached
|
||||
@@ -1116,7 +1116,7 @@ func TestOracleVerifiedPriceWithVerifier(t *testing.T) {
|
||||
oracle.AddSource("x-chain", src)
|
||||
|
||||
// Add verifier
|
||||
verifier := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
verifier := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
verifier.Start()
|
||||
oracle.SetVerifier(verifier)
|
||||
|
||||
@@ -1159,7 +1159,7 @@ func TestOracleStopWithVerifier(t *testing.T) {
|
||||
oracle := NewOracle()
|
||||
|
||||
// Add verifier
|
||||
verifier := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
verifier := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
verifier.Start()
|
||||
oracle.SetVerifier(verifier)
|
||||
|
||||
@@ -1228,7 +1228,7 @@ func TestVerifiedDataFields(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQChainVerifierBasic(t *testing.T) {
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
|
||||
// Start verifier
|
||||
if err := v.Start(); err != nil {
|
||||
@@ -1258,7 +1258,7 @@ func TestQChainVerifierBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQChainVerifierFinality(t *testing.T) {
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
v.Start()
|
||||
defer v.Close()
|
||||
|
||||
@@ -1284,7 +1284,7 @@ func TestQChainVerifierFinality(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQChainVerifierCrossChain(t *testing.T) {
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
v.Start()
|
||||
defer v.Close()
|
||||
|
||||
@@ -1304,7 +1304,7 @@ func TestQChainVerifierCrossChain(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQChainVerifierSetQuorum(t *testing.T) {
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
|
||||
// Default quorum
|
||||
v.SetQuorum(5)
|
||||
@@ -1314,7 +1314,7 @@ func TestQChainVerifierSetQuorum(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQChainVerifierFinalityLatency(t *testing.T) {
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
v := NewQChainVerifier("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
v.Start()
|
||||
defer v.Close()
|
||||
|
||||
@@ -1329,5 +1329,5 @@ func TestQChainVerifierFinalityLatency(t *testing.T) {
|
||||
|
||||
func TestQChainBackwardsCompatibility(t *testing.T) {
|
||||
// Test that QChainSource alias works
|
||||
var _ *QChainSource = NewQChainSource("http://localhost:9650/v1/bc/Q", "ws://localhost:9650/v1/bc/Q/ws")
|
||||
var _ *QChainSource = NewQChainSource("http://localhost:9650/v1/chain/Q", "ws://localhost:9650/v1/chain/Q/ws")
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ if curl -s -X POST --data '{
|
||||
"address":"X-lux18jma8ppw3nhx5r4ap8clazz0dps7rv5u6wdp",
|
||||
"assetID":"LUX"
|
||||
}
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/X 2>/dev/null | grep -q "balance"; then
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/X 2>/dev/null | grep -q "balance"; then
|
||||
echo -e "${GREEN}✅ Working${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Failed${NC}"
|
||||
@@ -171,7 +171,7 @@ if curl -s -X POST --data '{
|
||||
"method":"eth_chainId",
|
||||
"params":[],
|
||||
"id":1
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/C/rpc 2>/dev/null | grep -q "result"; then
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/C/rpc 2>/dev/null | grep -q "result"; then
|
||||
echo -e "${GREEN}✅ Working${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Failed${NC}"
|
||||
@@ -184,7 +184,7 @@ BLOCK_HEIGHT=$(curl -s -X POST --data '{
|
||||
"method":"eth_blockNumber",
|
||||
"params":[],
|
||||
"id":1
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/C/rpc 2>/dev/null | grep -o '"result":"[^"]*"' | sed 's/"result":"//;s/"//')
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/C/rpc 2>/dev/null | grep -o '"result":"[^"]*"' | sed 's/"result":"//;s/"//')
|
||||
|
||||
if [ ! -z "$BLOCK_HEIGHT" ]; then
|
||||
echo -e "${GREEN}✅ Current block: $BLOCK_HEIGHT${NC}"
|
||||
@@ -199,12 +199,12 @@ echo ""
|
||||
echo "RPC Endpoints:"
|
||||
echo " Info API: http://localhost:9650/v1/info"
|
||||
echo " Health: http://localhost:9650/v1/health"
|
||||
echo " X-Chain: http://localhost:9650/v1/bc/X"
|
||||
echo " C-Chain: http://localhost:9650/v1/bc/C/rpc"
|
||||
echo " P-Chain: http://localhost:9650/v1/bc/P"
|
||||
echo " X-Chain: http://localhost:9650/v1/chain/X"
|
||||
echo " C-Chain: http://localhost:9650/v1/chain/C/rpc"
|
||||
echo " P-Chain: http://localhost:9650/v1/chain/P"
|
||||
echo ""
|
||||
echo "WebSocket:"
|
||||
echo " C-Chain WS: ws://localhost:9650/v1/bc/C/ws"
|
||||
echo " C-Chain WS: ws://localhost:9650/v1/chain/C/ws"
|
||||
echo ""
|
||||
echo "Node PID: $NODE_PID"
|
||||
echo "To stop: kill $NODE_PID"
|
||||
@@ -220,7 +220,7 @@ while true; do
|
||||
"method":"eth_blockNumber",
|
||||
"params":[],
|
||||
"id":1
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/C/rpc 2>/dev/null | grep -o '"result":"[^"]*"' | sed 's/"result":"//;s/"//')
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/C/rpc 2>/dev/null | grep -o '"result":"[^"]*"' | sed 's/"result":"//;s/"//')
|
||||
|
||||
if [ ! -z "$BLOCK" ]; then
|
||||
BLOCK_DEC=$((16#${BLOCK#0x}))
|
||||
|
||||
+10
-10
@@ -136,17 +136,17 @@ test_endpoint "2. Keystore API" \
|
||||
|
||||
# Test X-Chain (AVM - Asset Virtual Machine)
|
||||
test_endpoint "3. X-Chain API" \
|
||||
"http://127.0.0.1:9650/v1/bc/X" \
|
||||
"http://127.0.0.1:9650/v1/chain/X" \
|
||||
'{"jsonrpc":"2.0","id":1,"method":"avm.getAssetDescription","params":{"assetID":"LUX"}}'
|
||||
|
||||
# Test P-Chain (Platform Chain)
|
||||
test_endpoint "4. P-Chain API" \
|
||||
"http://127.0.0.1:9650/v1/bc/P" \
|
||||
"http://127.0.0.1:9650/v1/chain/P" \
|
||||
'{"jsonrpc":"2.0","id":1,"method":"platform.getHeight"}'
|
||||
|
||||
# Test C-Chain (Contract Chain - EVM)
|
||||
test_endpoint "5. C-Chain API" \
|
||||
"http://127.0.0.1:9650/v1/bc/C/rpc" \
|
||||
"http://127.0.0.1:9650/v1/chain/C/rpc" \
|
||||
'{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'
|
||||
|
||||
# Get blockchain info
|
||||
@@ -172,7 +172,7 @@ curl -s -X POST --data '{
|
||||
"jsonrpc":"2.0",
|
||||
"id":1,
|
||||
"method":"avm.getHeight"
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/X 2>/dev/null | grep -o '"height":[0-9]*' || echo "Height: 0"
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/X 2>/dev/null | grep -o '"height":[0-9]*' || echo "Height: 0"
|
||||
|
||||
# Create test wallet
|
||||
echo ""
|
||||
@@ -199,7 +199,7 @@ X_ADDR=$(curl -s -X POST --data '{
|
||||
"username":"dexuser",
|
||||
"password":"dexpass123"
|
||||
}
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/X 2>/dev/null | grep -o '"address":"[^"]*"' | cut -d'"' -f4)
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/X 2>/dev/null | grep -o '"address":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ ! -z "$X_ADDR" ]; then
|
||||
echo -e "${GREEN}✅ X-Chain Address: $X_ADDR${NC}"
|
||||
@@ -212,9 +212,9 @@ echo ""
|
||||
echo "RPC Endpoints:"
|
||||
echo " Info API: http://localhost:9650/v1/info"
|
||||
echo " Health: http://localhost:9650/v1/health"
|
||||
echo " X-Chain: http://localhost:9650/v1/bc/X"
|
||||
echo " P-Chain: http://localhost:9650/v1/bc/P"
|
||||
echo " C-Chain: http://localhost:9650/v1/bc/C/rpc"
|
||||
echo " X-Chain: http://localhost:9650/v1/chain/X"
|
||||
echo " P-Chain: http://localhost:9650/v1/chain/P"
|
||||
echo " C-Chain: http://localhost:9650/v1/chain/C/rpc"
|
||||
echo ""
|
||||
echo "Node PID: $NODE_PID"
|
||||
echo "Logs: tail -f $DATA_DIR/node.log"
|
||||
@@ -231,7 +231,7 @@ while true; do
|
||||
"jsonrpc":"2.0",
|
||||
"id":1,
|
||||
"method":"avm.getHeight"
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/X 2>/dev/null | grep -o '"height":[0-9]*' | cut -d':' -f2)
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/X 2>/dev/null | grep -o '"height":[0-9]*' | cut -d':' -f2)
|
||||
|
||||
if [ ! -z "$HEIGHT" ]; then
|
||||
echo "X-Chain Height: $HEIGHT at $(date '+%H:%M:%S')"
|
||||
@@ -242,7 +242,7 @@ while true; do
|
||||
"jsonrpc":"2.0",
|
||||
"id":1,
|
||||
"method":"platform.getHeight"
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/bc/P 2>/dev/null | grep -o '"height":[0-9]*' | cut -d':' -f2)
|
||||
}' -H 'content-type:application/json;' http://127.0.0.1:9650/v1/chain/P 2>/dev/null | grep -o '"height":[0-9]*' | cut -d':' -f2)
|
||||
|
||||
if [ ! -z "$P_HEIGHT" ]; then
|
||||
echo "P-Chain Height: $P_HEIGHT"
|
||||
|
||||
Reference in New Issue
Block a user