feat(price-service/client): add out-of-order flag support

This commit is contained in:
Ali Behjati 2023-09-18 20:32:03 +02:00
parent 5e45146acb
commit d5c3090442
7 changed files with 55 additions and 12 deletions

10
package-lock.json generated
View File

@ -30590,6 +30590,7 @@
"version": "4.0.5", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz",
"integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
"hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"node-gyp-build": "^4.3.0" "node-gyp-build": "^4.3.0"
@ -30919,6 +30920,7 @@
"version": "5.0.7", "version": "5.0.7",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz",
"integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
"hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"node-gyp-build": "^4.3.0" "node-gyp-build": "^4.3.0"
@ -57438,7 +57440,7 @@
}, },
"price_service/client/js": { "price_service/client/js": {
"name": "@pythnetwork/price-service-client", "name": "@pythnetwork/price-service-client",
"version": "1.6.2", "version": "1.7.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@pythnetwork/price-service-sdk": "*", "@pythnetwork/price-service-sdk": "*",
@ -57964,7 +57966,7 @@
}, },
"target_chains/aptos/sdk/js": { "target_chains/aptos/sdk/js": {
"name": "@pythnetwork/pyth-aptos-js", "name": "@pythnetwork/pyth-aptos-js",
"version": "1.2.0", "version": "1.3.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@pythnetwork/price-service-client": "*", "@pythnetwork/price-service-client": "*",
@ -58133,7 +58135,7 @@
}, },
"target_chains/cosmwasm/sdk/js": { "target_chains/cosmwasm/sdk/js": {
"name": "@pythnetwork/pyth-terra-js", "name": "@pythnetwork/pyth-terra-js",
"version": "1.3.1", "version": "1.4.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@pythnetwork/price-service-client": "*", "@pythnetwork/price-service-client": "*",
@ -59678,7 +59680,7 @@
}, },
"target_chains/sui/sdk/js": { "target_chains/sui/sdk/js": {
"name": "@pythnetwork/pyth-sui-js", "name": "@pythnetwork/pyth-sui-js",
"version": "1.0.2", "version": "1.1.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@mysten/sui.js": "^0.37.1", "@mysten/sui.js": "^0.37.1",

View File

@ -1,6 +1,6 @@
{ {
"name": "@pythnetwork/price-service-client", "name": "@pythnetwork/price-service-client",
"version": "1.6.2", "version": "1.7.0",
"description": "Pyth price service client", "description": "Pyth price service client",
"author": { "author": {
"name": "Pyth Data Association" "name": "Pyth Data Association"

View File

@ -13,6 +13,8 @@ export type PriceFeedRequestConfig = {
verbose?: boolean; verbose?: boolean;
/* Optional binary to include the price feeds binary update data */ /* Optional binary to include the price feeds binary update data */
binary?: boolean; binary?: boolean;
/* Optional config for the websocket subscription to receive out of order updates */
allowOutOfOrder?: boolean;
}; };
export type PriceServiceConnectionConfig = { export type PriceServiceConnectionConfig = {
@ -38,6 +40,7 @@ type ClientMessage = {
ids: HexString[]; ids: HexString[];
verbose?: boolean; verbose?: boolean;
binary?: boolean; binary?: boolean;
allow_out_of_order?: boolean;
}; };
type ServerResponse = { type ServerResponse = {
@ -92,6 +95,7 @@ export class PriceServiceConnection {
this.priceFeedRequestConfig = { this.priceFeedRequestConfig = {
binary: config?.priceFeedRequestConfig?.binary, binary: config?.priceFeedRequestConfig?.binary,
verbose: config?.priceFeedRequestConfig?.verbose ?? config?.verbose, verbose: config?.priceFeedRequestConfig?.verbose ?? config?.verbose,
allowOutOfOrder: config?.priceFeedRequestConfig?.allowOutOfOrder,
}; };
this.priceFeedCallbacks = new Map(); this.priceFeedCallbacks = new Map();
@ -269,6 +273,7 @@ export class PriceServiceConnection {
type: "subscribe", type: "subscribe",
verbose: this.priceFeedRequestConfig.verbose, verbose: this.priceFeedRequestConfig.verbose,
binary: this.priceFeedRequestConfig.binary, binary: this.priceFeedRequestConfig.binary,
allow_out_of_order: this.priceFeedRequestConfig.allowOutOfOrder,
}; };
await this.wsClient?.send(JSON.stringify(message)); await this.wsClient?.send(JSON.stringify(message));
@ -352,6 +357,7 @@ export class PriceServiceConnection {
type: "subscribe", type: "subscribe",
verbose: this.priceFeedRequestConfig.verbose, verbose: this.priceFeedRequestConfig.verbose,
binary: this.priceFeedRequestConfig.binary, binary: this.priceFeedRequestConfig.binary,
allow_out_of_order: this.priceFeedRequestConfig.allowOutOfOrder,
}; };
this.logger.info("Resubscribing to existing price feeds."); this.logger.info("Resubscribing to existing price feeds.");

View File

@ -10,11 +10,11 @@ async function sleep(duration: DurationInMs): Promise<void> {
return new Promise((res) => setTimeout(res, duration)); return new Promise((res) => setTimeout(res, duration));
} }
// The endpoint is set to the price service endpoint in Tilt. // The endpoint is set to the price service endpoint.
// Please note that if you change it to a mainnet/testnet endpoint // Please note that if you change it to a mainnet/testnet endpoint
// some tests might fail due to the huge response size of a request // some tests might fail due to the huge response size of a request.
// , i.e. requesting latest price feeds or vaas of all price ids. // i.e. requesting latest price feeds or vaas of all price ids.
const PRICE_SERVICE_ENDPOINT = "http://pyth-price-server:4200"; const PRICE_SERVICE_ENDPOINT = "http://127.0.0.1:7575";
describe("Test http endpoints", () => { describe("Test http endpoints", () => {
test("Get price feed (without verbose/binary) works", async () => { test("Get price feed (without verbose/binary) works", async () => {
@ -193,4 +193,39 @@ describe("Test websocket endpoints", () => {
expect(observedFeeds.has(id)).toBe(true); expect(observedFeeds.has(id)).toBe(true);
} }
}); });
// This test only works on Hermes and is not stable because there might
// be no out of order updates. Hence the last check is commented out.
test.concurrent(
"websocket subscription works with allow out of order",
async () => {
const connection = new PriceServiceConnection(PRICE_SERVICE_ENDPOINT, {
priceFeedRequestConfig: { allowOutOfOrder: true, verbose: true },
});
const ids = await connection.getPriceFeedIds();
expect(ids.length).toBeGreaterThan(0);
const observedSlots: number[] = [];
await connection.subscribePriceFeedUpdates(ids, (priceFeed) => {
expect(priceFeed.getMetadata()).toBeDefined();
expect(priceFeed.getVAA()).toBeUndefined();
observedSlots.push(priceFeed.getMetadata()!.slot!);
});
// Wait for 20 seconds
await sleep(20000);
connection.closeWebSocket();
let seenOutOfOrder = false;
for (let i = 1; i < observedSlots.length; i++) {
if (observedSlots[i] < observedSlots[i - 1]) {
seenOutOfOrder = true;
}
}
// expect(seenOutOfOrder).toBe(true);
}
);
}); });

View File

@ -1,6 +1,6 @@
{ {
"name": "@pythnetwork/pyth-aptos-js", "name": "@pythnetwork/pyth-aptos-js",
"version": "1.2.0", "version": "1.3.0",
"description": "Pyth Network Aptos Utilities", "description": "Pyth Network Aptos Utilities",
"homepage": "https://pyth.network", "homepage": "https://pyth.network",
"author": { "author": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@pythnetwork/pyth-terra-js", "name": "@pythnetwork/pyth-terra-js",
"version": "1.3.1", "version": "1.4.0",
"description": "Pyth Network Terra Utils in JS", "description": "Pyth Network Terra Utils in JS",
"homepage": "https://pyth.network", "homepage": "https://pyth.network",
"author": { "author": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@pythnetwork/pyth-sui-js", "name": "@pythnetwork/pyth-sui-js",
"version": "1.0.2", "version": "1.1.0",
"description": "Pyth Network Sui Utilities", "description": "Pyth Network Sui Utilities",
"homepage": "https://pyth.network", "homepage": "https://pyth.network",
"author": { "author": {