浏览代码

[renderers-rust] Export discriminator constants for accounts and instructions (#721)

Loris Leiva 4 月之前
父节点
当前提交
a305a91e04
共有 25 个文件被更改,包括 186 次插入1 次删除
  1. 5 0
      .changeset/purple-melons-lie.md
  2. 2 0
      packages/renderers-rust/e2e/anchor/src/generated/accounts/guard_v1.rs
  3. 2 0
      packages/renderers-rust/e2e/anchor/src/generated/instructions/create_guard.rs
  4. 2 0
      packages/renderers-rust/e2e/anchor/src/generated/instructions/execute.rs
  5. 2 0
      packages/renderers-rust/e2e/anchor/src/generated/instructions/initialize.rs
  6. 2 0
      packages/renderers-rust/e2e/anchor/src/generated/instructions/update_guard.rs
  7. 2 0
      packages/renderers-rust/e2e/dummy/src/generated/instructions/instruction3.rs
  8. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/advance_nonce_account.rs
  9. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/allocate.rs
  10. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/allocate_with_seed.rs
  11. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/assign.rs
  12. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/assign_with_seed.rs
  13. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/authorize_nonce_account.rs
  14. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/create_account.rs
  15. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/create_account_with_seed.rs
  16. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/initialize_nonce_account.rs
  17. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/transfer_sol.rs
  18. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs
  19. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/upgrade_nonce_account.rs
  20. 2 0
      packages/renderers-rust/e2e/system/src/generated/instructions/withdraw_nonce_account.rs
  21. 2 0
      packages/renderers-rust/public/templates/accountsPage.njk
  22. 2 0
      packages/renderers-rust/public/templates/instructionsPage.njk
  23. 31 1
      packages/renderers-rust/src/getRenderMapVisitor.ts
  24. 107 0
      packages/renderers-rust/src/utils/discriminatorConstant.ts
  25. 1 0
      packages/renderers-rust/src/utils/index.ts

+ 5 - 0
.changeset/purple-melons-lie.md

@@ -0,0 +1,5 @@
+---
+'@codama/renderers-rust': patch
+---
+
+Export discriminator constants for accounts and instructions

+ 2 - 0
packages/renderers-rust/e2e/anchor/src/generated/accounts/guard_v1.rs

@@ -32,6 +32,8 @@ pub struct GuardV1 {
     pub additional_fields_rule: Vec<MetadataAdditionalFieldRule>,
 }
 
+pub const GUARD_V1_DISCRIMINATOR: [u8; 8] = [185, 149, 156, 78, 245, 108, 172, 68];
+
 impl GuardV1 {
     #[inline(always)]
     pub fn from_bytes(data: &[u8]) -> Result<Self, std::io::Error> {

+ 2 - 0
packages/renderers-rust/e2e/anchor/src/generated/instructions/create_guard.rs

@@ -11,6 +11,8 @@ use crate::generated::types::TransferAmountRule;
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const CREATE_GUARD_DISCRIMINATOR: [u8; 8] = [251, 254, 17, 198, 219, 218, 154, 99];
+
 /// Accounts.
 #[derive(Debug)]
 pub struct CreateGuard {

+ 2 - 0
packages/renderers-rust/e2e/anchor/src/generated/instructions/execute.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const EXECUTE_DISCRIMINATOR: [u8; 8] = [105, 37, 101, 197, 75, 251, 102, 26];
+
 /// Accounts.
 #[derive(Debug)]
 pub struct Execute {

+ 2 - 0
packages/renderers-rust/e2e/anchor/src/generated/instructions/initialize.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const INITIALIZE_DISCRIMINATOR: [u8; 8] = [43, 34, 13, 49, 167, 88, 235, 235];
+
 /// Accounts.
 #[derive(Debug)]
 pub struct Initialize {

+ 2 - 0
packages/renderers-rust/e2e/anchor/src/generated/instructions/update_guard.rs

@@ -11,6 +11,8 @@ use crate::generated::types::TransferAmountRule;
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const UPDATE_GUARD_DISCRIMINATOR: [u8; 8] = [51, 38, 175, 180, 25, 249, 39, 24];
+
 /// Accounts.
 #[derive(Debug)]
 pub struct UpdateGuard {

+ 2 - 0
packages/renderers-rust/e2e/dummy/src/generated/instructions/instruction3.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const INSTRUCTION3_DISCRIMINATOR: u32 = 42;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct Instruction3 {}

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/advance_nonce_account.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const ADVANCE_NONCE_ACCOUNT_DISCRIMINATOR: u32 = 4;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct AdvanceNonceAccount {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/allocate.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const ALLOCATE_DISCRIMINATOR: u32 = 8;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct Allocate {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/allocate_with_seed.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const ALLOCATE_WITH_SEED_DISCRIMINATOR: u32 = 9;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct AllocateWithSeed {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/assign.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const ASSIGN_DISCRIMINATOR: u32 = 1;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct Assign {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/assign_with_seed.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const ASSIGN_WITH_SEED_DISCRIMINATOR: u32 = 10;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct AssignWithSeed {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/authorize_nonce_account.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const AUTHORIZE_NONCE_ACCOUNT_DISCRIMINATOR: u32 = 7;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct AuthorizeNonceAccount {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/create_account.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const CREATE_ACCOUNT_DISCRIMINATOR: u32 = 0;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct CreateAccount {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/create_account_with_seed.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const CREATE_ACCOUNT_WITH_SEED_DISCRIMINATOR: u32 = 3;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct CreateAccountWithSeed {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/initialize_nonce_account.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const INITIALIZE_NONCE_ACCOUNT_DISCRIMINATOR: u32 = 6;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct InitializeNonceAccount {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/transfer_sol.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const TRANSFER_SOL_DISCRIMINATOR: u32 = 2;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct TransferSol {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs

@@ -9,6 +9,8 @@ use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 use solana_pubkey::Pubkey;
 
+pub const TRANSFER_SOL_WITH_SEED_DISCRIMINATOR: u32 = 11;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct TransferSolWithSeed {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/upgrade_nonce_account.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const UPGRADE_NONCE_ACCOUNT_DISCRIMINATOR: u32 = 12;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct UpgradeNonceAccount {

+ 2 - 0
packages/renderers-rust/e2e/system/src/generated/instructions/withdraw_nonce_account.rs

@@ -8,6 +8,8 @@
 use borsh::BorshDeserialize;
 use borsh::BorshSerialize;
 
+pub const WITHDRAW_NONCE_ACCOUNT_DISCRIMINATOR: u32 = 5;
+
 /// Accounts.
 #[derive(Debug)]
 pub struct WithdrawNonceAccount {

+ 2 - 0
packages/renderers-rust/public/templates/accountsPage.njk

@@ -12,6 +12,8 @@
 {{ nestedStruct }}
 {% endfor %}
 
+{{ discriminatorConstants }}
+
 impl {{ account.name | pascalCase }} {
   {% if account.size != null %}
     pub const LEN: usize = {{ account.size }};

+ 2 - 0
packages/renderers-rust/public/templates/instructionsPage.njk

@@ -5,6 +5,8 @@
 
 {{ imports }}
 
+{{ discriminatorConstants }}
+
 /// Accounts.
 #[derive(Debug)]
 pub struct {{ instruction.name | pascalCase }} {

+ 31 - 1
packages/renderers-rust/src/getRenderMapVisitor.ts

@@ -29,7 +29,14 @@ import {
 import { getTypeManifestVisitor } from './getTypeManifestVisitor';
 import { ImportMap } from './ImportMap';
 import { renderValueNode } from './renderValueNodeVisitor';
-import { getImportFromFactory, getTraitsFromNodeFactory, LinkOverrides, render, TraitOptions } from './utils';
+import {
+    getDiscriminatorConstants,
+    getImportFromFactory,
+    getTraitsFromNodeFactory,
+    LinkOverrides,
+    render,
+    TraitOptions,
+} from './utils';
 
 export type GetRenderMapOptions = {
     anchorTraits?: boolean;
@@ -61,6 +68,16 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                 visitAccount(node) {
                     const typeManifest = visit(node, typeManifestVisitor);
 
+                    // Discriminator constants.
+                    const fields = resolveNestedTypeNode(node.data).fields;
+                    const discriminatorConstants = getDiscriminatorConstants({
+                        discriminatorNodes: node.discriminators ?? [],
+                        fields,
+                        getImportFrom,
+                        prefix: node.name,
+                        typeManifestVisitor,
+                    });
+
                     // Seeds.
                     const seedsImports = new ImportMap();
                     const pda = node.pda ? linkables.get([...stack.getPath(), node.pda]) : undefined;
@@ -98,8 +115,10 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                             account: node,
                             anchorTraits,
                             constantSeeds,
+                            discriminatorConstants: discriminatorConstants.render,
                             hasVariableSeeds,
                             imports: imports
+                                .mergeWith(discriminatorConstants.imports)
                                 .remove(`generatedAccounts::${pascalCase(node.name)}`)
                                 .toString(dependencyMap),
                             pda,
@@ -139,6 +158,15 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                         );
                     }
 
+                    // Discriminator constants.
+                    const discriminatorConstants = getDiscriminatorConstants({
+                        discriminatorNodes: node.discriminators ?? [],
+                        fields: node.arguments,
+                        getImportFrom,
+                        prefix: node.name,
+                        typeManifestVisitor,
+                    });
+
                     // Instruction args.
                     const instructionArgs: {
                         default: boolean;
@@ -207,9 +235,11 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) {
                         `instructions/${snakeCase(node.name)}.rs`,
                         render('instructionsPage.njk', {
                             dataTraits: dataTraits.render,
+                            discriminatorConstants: discriminatorConstants.render,
                             hasArgs,
                             hasOptional,
                             imports: imports
+                                .mergeWith(discriminatorConstants.imports)
                                 .remove(`generatedInstructions::${pascalCase(node.name)}`)
                                 .toString(dependencyMap),
                             instruction: node,

+ 107 - 0
packages/renderers-rust/src/utils/discriminatorConstant.ts

@@ -0,0 +1,107 @@
+import {
+    camelCase,
+    ConstantDiscriminatorNode,
+    DiscriminatorNode,
+    FieldDiscriminatorNode,
+    InstructionArgumentNode,
+    isNode,
+    isNodeFilter,
+    snakeCase,
+    StructFieldTypeNode,
+    VALUE_NODES,
+} from '@codama/nodes';
+import { visit } from '@codama/visitors-core';
+
+import { getTypeManifestVisitor, TypeManifest } from '../getTypeManifestVisitor';
+import { ImportMap } from '../ImportMap';
+import { renderValueNode } from '../renderValueNodeVisitor';
+import { GetImportFromFunction } from './linkOverrides';
+
+type Fragment = { imports: ImportMap; render: string };
+
+function mergeFragments(fragments: Fragment[], merge: (parts: string[]) => string): Fragment {
+    const imports = fragments.reduce((acc, frag) => acc.mergeWith(frag.imports), new ImportMap());
+    const render = merge(fragments.map(frag => frag.render));
+    return { imports, render };
+}
+
+export function getDiscriminatorConstants(scope: {
+    discriminatorNodes: DiscriminatorNode[];
+    fields: InstructionArgumentNode[] | StructFieldTypeNode[];
+    getImportFrom: GetImportFromFunction;
+    prefix: string;
+    typeManifestVisitor: ReturnType<typeof getTypeManifestVisitor>;
+}): Fragment {
+    const fragments = scope.discriminatorNodes
+        .map(node => getDiscriminatorConstant(node, scope))
+        .filter(Boolean) as Fragment[];
+
+    return mergeFragments(fragments, r => r.join('\n\n'));
+}
+
+function getDiscriminatorConstant(
+    discriminatorNode: DiscriminatorNode,
+    scope: {
+        discriminatorNodes: DiscriminatorNode[];
+        fields: InstructionArgumentNode[] | StructFieldTypeNode[];
+        getImportFrom: GetImportFromFunction;
+        prefix: string;
+        typeManifestVisitor: ReturnType<typeof getTypeManifestVisitor>;
+    },
+) {
+    switch (discriminatorNode.kind) {
+        case 'constantDiscriminatorNode':
+            return getConstantDiscriminatorConstant(discriminatorNode, scope);
+        case 'fieldDiscriminatorNode':
+            return getFieldDiscriminatorConstant(discriminatorNode, scope);
+        default:
+            return null;
+    }
+}
+
+function getConstantDiscriminatorConstant(
+    discriminatorNode: ConstantDiscriminatorNode,
+    scope: {
+        discriminatorNodes: DiscriminatorNode[];
+        getImportFrom: GetImportFromFunction;
+        prefix: string;
+        typeManifestVisitor: ReturnType<typeof getTypeManifestVisitor>;
+    },
+): Fragment {
+    const { discriminatorNodes, getImportFrom, prefix, typeManifestVisitor } = scope;
+
+    const index = discriminatorNodes.filter(isNodeFilter('constantDiscriminatorNode')).indexOf(discriminatorNode);
+    const suffix = index <= 0 ? '' : `_${index + 1}`;
+
+    const name = camelCase(`${prefix}_discriminator${suffix}`);
+    const typeManifest = visit(discriminatorNode.constant.type, typeManifestVisitor);
+    const value = renderValueNode(discriminatorNode.constant.value, getImportFrom);
+    return getConstant(name, typeManifest, value);
+}
+
+function getFieldDiscriminatorConstant(
+    discriminatorNode: FieldDiscriminatorNode,
+    scope: {
+        fields: InstructionArgumentNode[] | StructFieldTypeNode[];
+        getImportFrom: GetImportFromFunction;
+        prefix: string;
+        typeManifestVisitor: ReturnType<typeof getTypeManifestVisitor>;
+    },
+): Fragment | null {
+    const { fields, prefix, getImportFrom, typeManifestVisitor } = scope;
+
+    const field = fields.find(f => f.name === discriminatorNode.name);
+    if (!field || !field.defaultValue || !isNode(field.defaultValue, VALUE_NODES)) {
+        return null;
+    }
+
+    const name = camelCase(`${prefix}_${discriminatorNode.name}`);
+    const typeManifest = visit(field.type, typeManifestVisitor);
+    const value = renderValueNode(field.defaultValue, getImportFrom);
+    return getConstant(name, typeManifest, value);
+}
+
+function getConstant(name: string, typeManifest: TypeManifest, value: Fragment): Fragment {
+    const type: Fragment = { imports: typeManifest.imports, render: typeManifest.type };
+    return mergeFragments([type, value], ([t, v]) => `pub const ${snakeCase(name).toUpperCase()}: ${t} = ${v};`);
+}

+ 1 - 0
packages/renderers-rust/src/utils/index.ts

@@ -1,4 +1,5 @@
 export * from './codecs';
+export * from './discriminatorConstant';
 export * from './linkOverrides';
 export * from './render';
 export * from './traitOptions';