Explorar o código

feat(xc_admin_cli): support idl upgrades (#1935)

* go

* go

* fix: ts-node to devdependencies
guibescos hai 1 ano
pai
achega
d63f93375b

+ 3 - 0
governance/xc_admin/packages/xc_admin_cli/package.json

@@ -32,5 +32,8 @@
     "@sqds/mesh": "^1.0.6",
     "commander": "^9.5.0",
     "typescript": "^4.9.4"
+  },
+  "dev-dependencies": {
+    "ts-node": "^10.9.2"
   }
 }

+ 25 - 0
governance/xc_admin/packages/xc_admin_cli/src/index.ts

@@ -44,6 +44,7 @@ import {
   findDetermisticStakeAccountAddress,
   getMultisigCluster,
   getProposalInstructions,
+  idlSetBuffer,
   isPriceStorePublisherInitialized,
 } from "@pythnetwork/xc-admin-common";
 
@@ -284,6 +285,30 @@ multisigCommand("upgrade-program", "Upgrade a program from a buffer")
     );
   });
 
+multisigCommand("upgrade-idl", "Upgrade an Anchor Idl from a bufffer")
+  .requiredOption(
+    "-p, --program-id <pubkey>",
+    "program whose idl you want to upgrade"
+  )
+  .requiredOption("-b, --buffer <pubkey>", "buffer account")
+  .action(async (options: any) => {
+    const vault = await loadVaultFromOptions(options);
+    const cluster: PythCluster = options.cluster;
+    const programId: PublicKey = new PublicKey(options.programId);
+    const buffer: PublicKey = new PublicKey(options.buffer);
+
+    const proposalInstruction: TransactionInstruction = await idlSetBuffer(
+      programId,
+      buffer,
+      await vault.getVaultAuthorityPDA(cluster)
+    );
+
+    await vault.proposeInstructions(
+      [proposalInstruction],
+      cluster,
+      DEFAULT_PRIORITY_FEE_CONFIG
+    );
+  });
 async function closeProgramOrBuffer(
   vault: MultisigVault,
   cluster: PythCluster,

+ 22 - 1
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/MessageBufferMultisigInstruction.ts

@@ -4,7 +4,11 @@ import {
   UNRECOGNIZED_INSTRUCTION,
   UnrecognizedProgram,
 } from ".";
-import { AnchorAccounts, resolveAccountNames } from "./anchor";
+import {
+  AnchorAccounts,
+  IDL_SET_BUFFER_DISCRIMINATOR,
+  resolveAccountNames,
+} from "./anchor";
 import messageBufferIdl from "message_buffer/idl/message_buffer.json";
 import { PublicKey, TransactionInstruction } from "@solana/web3.js";
 import { Idl, BorshCoder } from "@coral-xyz/anchor";
@@ -66,6 +70,23 @@ export class AnchorMultisigInstruction implements MultisigInstruction {
       default:
         return UnrecognizedProgram.fromTransactionInstruction(instruction);
     }
+
+    /// Special case for IDL instructions that all programs have
+    if (instruction.data.equals(IDL_SET_BUFFER_DISCRIMINATOR)) {
+      return new AnchorMultisigInstruction(
+        program,
+        "IdlSetBuffer",
+        {},
+        {
+          named: {
+            buffer: instruction.keys[0],
+            idlAccount: instruction.keys[1],
+            idlAuthority: instruction.keys[2],
+          },
+          remaining: instruction.keys.slice(3),
+        }
+      );
+    }
     const instructionCoder = new BorshCoder(idl).instruction;
 
     const deserializedData = instructionCoder.decode(instruction.data);

+ 36 - 1
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/anchor.ts

@@ -1,5 +1,9 @@
 import { Idl } from "@coral-xyz/anchor";
-import { AccountMeta, TransactionInstruction } from "@solana/web3.js";
+import {
+  AccountMeta,
+  PublicKey,
+  TransactionInstruction,
+} from "@solana/web3.js";
 
 type NamedAccounts = Record<string, AccountMeta>;
 type RemainingAccounts = AccountMeta[];
@@ -28,3 +32,34 @@ export function resolveAccountNames(
   });
   return { named, remaining };
 }
+
+export const IDL_SET_BUFFER_DISCRIMINATOR = Buffer.from(
+  "40f4bc78a7e9690a03",
+  "hex"
+);
+
+async function getIdlAddress(programId: PublicKey): Promise<PublicKey> {
+  const programSigner = PublicKey.findProgramAddressSync([], programId)[0];
+  return PublicKey.createWithSeed(programSigner, "anchor:idl", programId);
+}
+
+export async function idlSetBuffer(
+  programId: PublicKey,
+  buffer: PublicKey,
+  idlAuthority: PublicKey
+): Promise<TransactionInstruction> {
+  let idlAddress = await getIdlAddress(programId);
+  return {
+    programId,
+    data: IDL_SET_BUFFER_DISCRIMINATOR,
+    keys: [
+      { pubkey: buffer, isSigner: false, isWritable: true },
+      { pubkey: idlAddress, isSigner: false, isWritable: true },
+      {
+        pubkey: idlAuthority,
+        isSigner: true,
+        isWritable: true,
+      },
+    ],
+  };
+}

+ 1 - 0
governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts

@@ -167,6 +167,7 @@ export class MultisigParser {
   }
 }
 
+export { idlSetBuffer } from "./anchor";
 export { WormholeMultisigInstruction } from "./WormholeMultisigInstruction";
 export { PythMultisigInstruction } from "./PythMultisigInstruction";
 export { AnchorMultisigInstruction } from "./MessageBufferMultisigInstruction";

+ 24 - 23
pnpm-lock.yaml

@@ -314,7 +314,7 @@ importers:
         version: 2.8.8
       ts-jest:
         specifier: ^29.1.1
-        version: 29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@22.5.1)(ts-node@10.9.1(@types/node@22.5.1)(typescript@5.4.5)))(typescript@5.4.5)
+        version: 29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.22.0)(jest@29.7.0(@types/node@22.5.1)(ts-node@10.9.1(@types/node@22.5.1)(typescript@5.4.5)))(typescript@5.4.5)
       ts-node:
         specifier: ^10.9.1
         version: 10.9.1(@types/node@22.5.1)(typescript@5.4.5)
@@ -36141,14 +36141,14 @@ snapshots:
     dependencies:
       acorn: 8.12.1
 
-  acorn-jsx@5.3.2(acorn@8.11.3):
-    dependencies:
-      acorn: 8.11.3
-
   acorn-jsx@5.3.2(acorn@8.12.0):
     dependencies:
       acorn: 8.12.0
 
+  acorn-jsx@5.3.2(acorn@8.12.1):
+    dependencies:
+      acorn: 8.12.1
+
   acorn-node@1.8.2:
     dependencies:
       acorn: 7.4.1
@@ -40231,8 +40231,8 @@ snapshots:
 
   espree@9.6.1:
     dependencies:
-      acorn: 8.11.3
-      acorn-jsx: 5.3.2(acorn@8.11.3)
+      acorn: 8.12.1
+      acorn-jsx: 5.3.2(acorn@8.12.1)
       eslint-visitor-keys: 3.4.3
 
   esprima@4.0.1: {}
@@ -50342,28 +50342,29 @@ snapshots:
     dependencies:
       tslib: 2.6.3
 
-  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@16.18.101)(ts-node@10.9.2(@types/node@16.18.101)(typescript@4.9.5)))(typescript@4.9.5):
+  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(esbuild@0.22.0)(jest@29.7.0(@types/node@22.5.1)(ts-node@10.9.1(@types/node@22.5.1)(typescript@5.4.5)))(typescript@5.4.5):
     dependencies:
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@16.18.101)(ts-node@10.9.2(@types/node@16.18.101)(typescript@4.9.5))
+      jest: 29.7.0(@types/node@22.5.1)(ts-node@10.9.1(@types/node@22.5.1)(typescript@5.4.5))
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
       make-error: 1.3.6
       semver: 7.6.0
-      typescript: 4.9.5
+      typescript: 5.4.5
       yargs-parser: 21.1.1
     optionalDependencies:
       '@babel/core': 7.24.7
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.24.7)
+      esbuild: 0.22.0
 
-  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@4.9.5)))(typescript@4.9.5):
+  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@16.18.101)(ts-node@10.9.2(@types/node@16.18.101)(typescript@4.9.5)))(typescript@4.9.5):
     dependencies:
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@4.9.5))
+      jest: 29.7.0(@types/node@16.18.101)(ts-node@10.9.2(@types/node@16.18.101)(typescript@4.9.5))
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
@@ -50376,45 +50377,45 @@ snapshots:
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.24.7)
 
-  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@5.4.5)))(typescript@5.4.5):
+  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@4.9.5)))(typescript@4.9.5):
     dependencies:
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@5.4.5))
+      jest: 29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@4.9.5))
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
       make-error: 1.3.6
       semver: 7.6.0
-      typescript: 5.4.5
+      typescript: 4.9.5
       yargs-parser: 21.1.1
     optionalDependencies:
       '@babel/core': 7.24.7
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.24.7)
 
-  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@18.19.34)(ts-node@10.9.2(@types/node@18.19.34)(typescript@4.9.5)))(typescript@4.9.5):
+  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@5.4.5)))(typescript@5.4.5):
     dependencies:
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@18.19.34)(ts-node@10.9.2(@types/node@18.19.34)(typescript@4.9.5))
+      jest: 29.7.0(@types/node@18.11.18)(ts-node@10.9.2(@types/node@18.11.18)(typescript@5.4.5))
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
       make-error: 1.3.6
       semver: 7.6.0
-      typescript: 4.9.5
+      typescript: 5.4.5
       yargs-parser: 21.1.1
     optionalDependencies:
       '@babel/core': 7.24.7
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.24.7)
 
-  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@4.9.5)))(typescript@4.9.5):
+  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@18.19.34)(ts-node@10.9.2(@types/node@18.19.34)(typescript@4.9.5)))(typescript@4.9.5):
     dependencies:
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@4.9.5))
+      jest: 29.7.0(@types/node@18.19.34)(ts-node@10.9.2(@types/node@18.19.34)(typescript@4.9.5))
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
@@ -50427,17 +50428,17 @@ snapshots:
       '@jest/types': 29.6.3
       babel-jest: 29.7.0(@babel/core@7.24.7)
 
-  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@22.5.1)(ts-node@10.9.1(@types/node@22.5.1)(typescript@5.4.5)))(typescript@5.4.5):
+  ts-jest@29.1.2(@babel/core@7.24.7)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.7))(jest@29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@4.9.5)))(typescript@4.9.5):
     dependencies:
       bs-logger: 0.2.6
       fast-json-stable-stringify: 2.1.0
-      jest: 29.7.0(@types/node@22.5.1)(ts-node@10.9.1(@types/node@22.5.1)(typescript@5.4.5))
+      jest: 29.7.0(@types/node@20.14.2)(ts-node@10.9.2(@types/node@20.14.2)(typescript@4.9.5))
       jest-util: 29.7.0
       json5: 2.2.3
       lodash.memoize: 4.1.2
       make-error: 1.3.6
       semver: 7.6.0
-      typescript: 5.4.5
+      typescript: 4.9.5
       yargs-parser: 21.1.1
     optionalDependencies:
       '@babel/core': 7.24.7