Переглянути джерело

feat(price_pusher): make jito bundles independent (#1565)

* Checkpoint

* bump

* Comment

* Fix

* Improvde test
guibescos 1 рік тому
батько
коміт
641a4bdd63

+ 1 - 1
apps/price_pusher/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/price-pusher",
-  "version": "6.7.2",
+  "version": "6.8.0",
   "description": "Pyth Price Pusher",
   "homepage": "https://pyth.network",
   "main": "lib/index.js",

+ 23 - 38
apps/price_pusher/src/solana/solana.ts

@@ -12,6 +12,7 @@ import {
   sendTransactionsJito,
 } from "@pythnetwork/solana-utils";
 import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher";
+import { sliceAccumulatorUpdateData } from "@pythnetwork/price-service-sdk";
 
 export class SolanaPriceListener extends ChainPriceListener {
   constructor(
@@ -107,6 +108,8 @@ export class SolanaPricePusher implements IPricePusher {
   }
 }
 
+const UPDATES_PER_JITO_BUNDLE = 7;
+
 export class SolanaPricePusherJito implements IPricePusher {
   constructor(
     private pythSolanaReceiver: PythSolanaReceiver,
@@ -121,7 +124,7 @@ export class SolanaPricePusherJito implements IPricePusher {
     priceIds: string[],
     pubTimesToPush: number[]
   ): Promise<void> {
-    let priceFeedUpdateData;
+    let priceFeedUpdateData: string[];
     try {
       priceFeedUpdateData = await this.priceServiceConnection.getLatestVaas(
         priceIds
@@ -131,47 +134,29 @@ export class SolanaPricePusherJito implements IPricePusher {
       return;
     }
 
-    const transactionBuilder = this.pythSolanaReceiver.newTransactionBuilder({
-      closeUpdateAccounts: false,
-    });
-    await transactionBuilder.addUpdatePriceFeed(
-      priceFeedUpdateData,
-      this.shardId
-    );
-    await transactionBuilder.addClosePreviousEncodedVaasInstructions();
-
-    const transactions = await transactionBuilder.buildVersionedTransactions({
-      jitoTipLamports: this.jitoTipLamports,
-      tightComputeBudget: true,
-      jitoBundleSize: this.jitoBundleSize,
-    });
-
-    const firstSignature = await sendTransactionsJito(
-      transactions.slice(0, this.jitoBundleSize),
-      this.searcherClient,
-      this.pythSolanaReceiver.wallet
-    );
+    for (let i = 0; i < priceIds.length; i += UPDATES_PER_JITO_BUNDLE) {
+      const transactionBuilder = this.pythSolanaReceiver.newTransactionBuilder({
+        closeUpdateAccounts: true,
+      });
+      await transactionBuilder.addUpdatePriceFeed(
+        priceFeedUpdateData.map((x) => {
+          return sliceAccumulatorUpdateData(
+            Buffer.from(x, "base64"),
+            i,
+            i + UPDATES_PER_JITO_BUNDLE
+          ).toString("base64");
+        }),
+        this.shardId
+      );
 
-    const blockhashResult =
-      await this.pythSolanaReceiver.connection.getLatestBlockhashAndContext({
-        commitment: "confirmed",
+      const transactions = await transactionBuilder.buildVersionedTransactions({
+        jitoTipLamports: this.jitoTipLamports,
+        tightComputeBudget: true,
+        jitoBundleSize: this.jitoBundleSize,
       });
-    await this.pythSolanaReceiver.connection.confirmTransaction(
-      {
-        signature: firstSignature,
-        blockhash: blockhashResult.value.blockhash,
-        lastValidBlockHeight: blockhashResult.value.lastValidBlockHeight,
-      },
-      "confirmed"
-    );
 
-    for (
-      let i = this.jitoBundleSize;
-      i < transactions.length;
-      i += this.jitoBundleSize
-    ) {
       await sendTransactionsJito(
-        transactions.slice(i, i + this.jitoBundleSize),
+        transactions,
         this.searcherClient,
         this.pythSolanaReceiver.wallet
       );

+ 2 - 2
package-lock.json

@@ -47,7 +47,7 @@
     },
     "apps/price_pusher": {
       "name": "@pythnetwork/price-pusher",
-      "version": "6.7.2",
+      "version": "6.8.0",
       "license": "Apache-2.0",
       "dependencies": {
         "@injectivelabs/sdk-ts": "1.10.72",
@@ -65701,7 +65701,7 @@
     },
     "price_service/sdk/js": {
       "name": "@pythnetwork/price-service-sdk",
-      "version": "1.6.1",
+      "version": "1.7.0",
       "license": "Apache-2.0",
       "devDependencies": {
         "@types/jest": "^29.4.0",

+ 1 - 1
price_service/sdk/js/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/price-service-sdk",
-  "version": "1.6.1",
+  "version": "1.7.0",
   "description": "Pyth price service SDK",
   "homepage": "https://pyth.network",
   "main": "lib/index.js",

+ 53 - 0
price_service/sdk/js/src/AccumulatorUpdateData.ts

@@ -64,6 +64,59 @@ export function parsePriceFeedMessage(message: Buffer): PriceFeedMessage {
   };
 }
 
+/**
+ * An AccumulatorUpdateData contains a VAA and a list of updates. This function returns a new serialized AccumulatorUpdateData with only the updates in the range [start, end).
+ */
+export function sliceAccumulatorUpdateData(
+  data: Buffer,
+  start?: number,
+  end?: number
+): Buffer {
+  if (!isAccumulatorUpdateData(data)) {
+    throw new Error("Invalid accumulator message");
+  }
+  let cursor = 6;
+  const trailingPayloadSize = data.readUint8(cursor);
+  cursor += 1 + trailingPayloadSize;
+
+  // const proofType = data.readUint8(cursor);
+  cursor += 1;
+
+  const vaaSize = data.readUint16BE(cursor);
+  cursor += 2;
+  cursor += vaaSize;
+
+  const endOfVaa = cursor;
+
+  const updates = [];
+  const numUpdates = data.readUInt8(cursor);
+  cursor += 1;
+
+  for (let i = 0; i < numUpdates; i++) {
+    const updateStart = cursor;
+    const messageSize = data.readUint16BE(cursor);
+    cursor += 2;
+    cursor += messageSize;
+
+    const numProofs = data.readUInt8(cursor);
+    cursor += 1;
+    cursor += KECCAK160_HASH_SIZE * numProofs;
+
+    updates.push(data.subarray(updateStart, cursor));
+  }
+
+  if (cursor !== data.length) {
+    throw new Error("Didn't reach the end of the message");
+  }
+
+  const sliceUpdates = updates.slice(start, end);
+  return Buffer.concat([
+    data.subarray(0, endOfVaa),
+    Buffer.from([sliceUpdates.length]),
+    ...updates.slice(start, end),
+  ]);
+}
+
 export function parseAccumulatorUpdateData(
   data: Buffer
 ): AccumulatorUpdateData {

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
price_service/sdk/js/src/__tests__/AccumulatorUpdateData.test.ts


+ 1 - 0
price_service/sdk/js/src/index.ts

@@ -11,6 +11,7 @@ export type HexString = string;
 
 export {
   isAccumulatorUpdateData,
+  sliceAccumulatorUpdateData,
   parseAccumulatorUpdateData,
   AccumulatorUpdateData,
   parsePriceFeedMessage,

Деякі файли не було показано, через те що забагато файлів було змінено