gagliardetto / anchor-go

Generate Go clients from anchor IDLs for Solana blockchain programs
MIT License
138 stars 31 forks source link

Anchor error -- InstructionDidNotDeserialize #10

Open nathanleclaire opened 2 years ago

nathanleclaire commented 2 years ago

I'm getting back a weird error on my transaction --

(*solana.Transaction)(0x14000124070)(   
   ├─ Signatures[len=1]
   │    └─ 3UpnFHfN9d9ZTHsiaL2JswkFxBkzYDRHAB8CwKYdhYJQiAmuP83vYST7XKY9XMyCzd6AP7thHBjisBBBzKSYb39N
   ├─ Message
   │    ├─ RecentBlockhash: 752C7hsnWjHbz6diYE29tm2MfeQnMA1U1w3WMSQUCzin
   │    ├─ AccountKeys[len=4]
   │    │    ├─ 4GBYBnYu2Nk7yP4zuNX5kpWoienPdu5TAvutLcJHf1YL
   │    │    ├─ ADxdmsoW5xhtBJ44cmoPyQpvBj2rWSvgnSTS78SSBvBQ
   │    │    ├─ 11111111111111111111111111111111
   │    │    └─ EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
   │    └─ Header
   │       ├─ NumRequiredSignatures: 1
   │       ├─ NumReadonlySignedAccounts: 0
   │       └─ NumReadonlyUnsignedAccounts: 2
   └─ Instructions[len=1]
      └─ Program: Worknet EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
         └─ Instruction: UpdateDevice
            ├─ Params[len=1]
            │    └─ Device: (worknet.Device) {
            │                Ipv4: ([4]uint8) (len=4 cap=4) {
            │                 00000000  00 00 00 00                                       |....|
            │                },
            │                Hostname: (string) "",
            │                Bump: (uint8) 255,
            │                Status: (worknet.DeviceStatus) Registered,
            │                DeviceAuthority: (solana.PublicKey) (len=32 cap=32) 4GBYBnYu2Nk7yP4zuNX5kpWoienPdu5TAvutLcJHf1YL
            │               }
            └─ Accounts[len=3]
               ├─ deviceAuthority: 4GBYBnYu2Nk7yP4zuNX5kpWoienPdu5TAvutLcJHf1YL [WRITE, SIGN] 
               ├─          device: ADxdmsoW5xhtBJ44cmoPyQpvBj2rWSvgnSTS78SSBvBQ [WRITE] 
               └─   systemProgram: 11111111111111111111111111111111 [] 
)
daoctl: error: (*jsonrpc.RPCError)(0x14000119200)({
                Code: (int) -32002,
                Message: (string) (len=89) "Transaction simulation failed: Error processing Instruction 0: custom program error: 0x66",
                Data: (map[string]interface {}) (len=4) {
                 (string) (len=8) "accounts": (interface {}) <nil>,
                 (string) (len=3) "err": (map[string]interface {}) (len=1) {
                  (string) (len=16) "InstructionError": ([]interface {}) (len=2 cap=2) {
                   (json.Number) (len=1) "0",
                   (map[string]interface {}) (len=1) {
                    (string) (len=6) "Custom": (json.Number) (len=3) "102"
                   }
                  }
                 },
                 (string) (len=4) "logs": ([]interface {}) (len=5 cap=8) {
                  (string) (len=63) "Program EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9 invoke [1]",
                  (string) (len=38) "Program log: Instruction: UpdateDevice",
                  (string) (len=167) "Program log: AnchorError occurred. Error Code: InstructionDidNotDeserialize. Error Number: 102. Error Message: The program could not deserialize the given instruction.",
                  (string) (len=90) "Program EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9 consumed 3587 of 200000 compute units",
                  (string) (len=87) "Program EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9 failed: custom program error: 0x66"
                 },
                 (string) (len=13) "unitsConsumed": (json.Number) (len=1) "0"
                }
               })

the transaction message:

(solana.Message) {
 AccountKeys: ([]solana.PublicKey) (len=4 cap=4) {
  (solana.PublicKey) (len=32 cap=32) 4GBYBnYu2Nk7yP4zuNX5kpWoienPdu5TAvutLcJHf1YL,
  (solana.PublicKey) (len=32 cap=32) ADxdmsoW5xhtBJ44cmoPyQpvBj2rWSvgnSTS78SSBvBQ,
  (solana.PublicKey) (len=32 cap=32) 11111111111111111111111111111111,
  (solana.PublicKey) (len=32 cap=32) EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
 },
 Header: (solana.MessageHeader) {
  NumRequiredSignatures: (uint8) 1,
  NumReadonlySignedAccounts: (uint8) 0,
  NumReadonlyUnsignedAccounts: (uint8) 2
 },
 RecentBlockhash: (solana.Hash) (len=32 cap=32) 752C7hsnWjHbz6diYE29tm2MfeQnMA1U1w3WMSQUCzin,
 Instructions: ([]solana.CompiledInstruction) (len=1 cap=1) {
  (solana.CompiledInstruction) {
   ProgramIDIndex: (uint16) 3,
   Accounts: ([]uint16) (len=3 cap=3) {
    (uint16) 0,
    (uint16) 1,
    (uint16) 2
   },
   Data: (solana.Base58) (len=58 cap=64) H9VJg8bfvmqXHgp785X5L6pv2W1DSNfH1GW48BqQ8rU8feZcSosi67B44b1oUJyW9rZrZFdaBh8DHiG
  }
 }
}

It's peculiar. I have the Go bindings working just fine with the RegisterDevice instruction, which is barely different from UpdateDevice that's throwing off the error here.

#[account]
#[derive(Default)]
pub struct Device {
    pub ipv4: [u8; 4],
    pub hostname: String,
    pub bump: u8,
    pub status: DeviceStatus,
    pub device_authority: Pubkey,
}

#[derive(Accounts)]
pub struct UpdateDevice<'info> {
    pub device_authority: Signer<'info>,

    #[account(mut,
        has_one = device_authority,
        seeds = [device.device_authority.key().as_ref()],
        bump,
    )]
    pub device: Box<Account<'info, Device>>,

    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
#[instruction(device_authority: Pubkey)]
pub struct RegisterDevice<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,

    #[account(init,
        space = 128,
        seeds = [device_authority.as_ref()],
        bump,
        payer = authority,
    )]
    pub device: Box<Account<'info, Device>>,

    pub system_program: Program<'info, System>,
}

My Anchor test for the same endpoint works fine 🤷

it("updates device info", async () => {
        const [devicePDA, _devicePDABump] =
            await anchor.web3.PublicKey.findProgramAddress(
                [deviceKey.publicKey.toBuffer()],
                program.programId
            );
        await program.methods
            .updateDevice({
                ipv4: [10, 10, 10, 10],
                hostname: "testhost",
                status: { registered: {} }, // TODO: better way to get enum?
                deviceAuthority: deviceKey.publicKey,
            })
            .accounts({
                deviceAuthority: deviceKey.publicKey,
                device: devicePDA,
                systemProgram: SystemProgram.programId,
            })
            .signers([deviceKey])
            .rpc();
    });

Any ideas?

nathanleclaire commented 2 years ago

@gagliardetto lmk if anything stands out to you

nathanleclaire commented 2 years ago

Hmmm so, some additional information from experimentation -- if I remove the device instruction parameter (i.e., the Device struct) -- I don't get the error. Perhaps the bindings aren't encoding the parameter correctly? (This is Anchor 0.24.2 by the way)

nathanleclaire commented 2 years ago

Splitting the Device struct into individual args works...

(*solana.Transaction)(0x140000c60e0)(   
   ├─ Signatures[len=1]
   │    └─ 4MpGtFh84ntJTjqaFoHHgLzkpsaesxyWeL6MZCwFFpgiuX6fPxrhPacb3qDd3UjRCguQU1cmcGn7tvjSpUZRpbvf
   ├─ Message
   │    ├─ RecentBlockhash: AmuXnDNuugCGUsUvbt6ai7Zwf3221GebJZVR332u5dyn
   │    ├─ AccountKeys[len=4]
   │    │    ├─ Gr1LZxEY1TGiVdJ4GvgKt9DSv9x6WUZaTS91nu3S3Ej3
   │    │    ├─ 7YpAsJZQvapwo1pT2RQTg2zkFffHN5Au1MUoyUGuTWhr
   │    │    ├─ 11111111111111111111111111111111
   │    │    └─ EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
   │    └─ Header
   │       ├─ NumRequiredSignatures: 1
   │       ├─ NumReadonlySignedAccounts: 0
   │       └─ NumReadonlyUnsignedAccounts: 2
   └─ Instructions[len=1]
      └─ Program: Worknet EdUCoDdRnT5HsQ2Ejy3TWMTQP8iUyMQB4WzoNh45pNX9
         └─ Instruction: UpdateDevice
            ├─ Params[len=4]
            │    ├─     Ipv4: ([4]uint8) (len=4 cap=4) {
            │    │             00000000  00 00 00 00                                       |....|
            │    │            }
            │    ├─ Hostname: (string) (len=3) "foo"
            │    ├─     Bump: (uint8) 255
            │    └─   Status: (worknet.DeviceStatus) Registered
            └─ Accounts[len=3]
               ├─ deviceAuthority: Gr1LZxEY1TGiVdJ4GvgKt9DSv9x6WUZaTS91nu3S3Ej3 [WRITE, SIGN] 
               ├─          device: 7YpAsJZQvapwo1pT2RQTg2zkFffHN5Au1MUoyUGuTWhr [WRITE] 
               └─   systemProgram: 11111111111111111111111111111111 [] 
)

But that's kind of a bummer, I expected to be able to pass a whole Device struct. That should work right?