0

I have the following struct defined in the Solana anchor program

#[account]
pub struct Parent {
    pub field1: String,
    pub data_arr: Vec<Data>,
}

#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)]
pub struct Data {
    pub field1: String,
    pub field2: f64,
    pub field3: u8,
}

And I have this function that pushes the given data into the data_arr Vector

pub push_data(ctx: Context<AddData>, data: Vec<Data>)  -> Result<()> {
    ...
    parent_account.data_arr.push(data);

    Ok(())
}

I am trying to call this instruction using Solana web3js library by creating a transaction instruction and passing the data buffer. It works for data types like String, u8, f64, etc. But I am getting the following error when trying to send this custom struct data,

Error: 'Program log: AnchorError occurred. Error Code: InstructionDidNotDeserialize. Error Number: 102. Error Message: The program could not deserialize the given instruction.',

I followed this method: How to serialize instruction buffer for an Anchor program

...

// data that actually needs to be serialized
// const data = [{ field1: 'str1', field2: 22.12, field3: 2 }, { field1: 'str2', field2: 29.21, field3: 8 }];

// serializing a string parameter
const data = 'sample data';

const string_u8vec = new TextEncoder().encode(data)
const string_u8vec_length = Buffer.from(new Uint8Array(new BN(string_u8vec.length).toArray("le", 4)));

const instructionBuffer = Buffer.concat([
   ixBuffer,            // namespace+method_name
   string_u8vec_length, // the length of the string
   string_u8vec         // the string itself
])

...

The above approach works if the data is a string. How to generate the data buffer if we need to pass other data types like PubKey, and Custom structs like the above one. Please help. Thanks.

1 Answer 1

1

For your custom struct, you'll follow a similar process, but one more layer of indirection since it's a Vec<Data>, meaning:

const data = [{ field1: '0', field2: '0'}, { field1: '1', field2: '1'}];

// serializing the data length
const data_length = Buffer.allocUnsafe(4);
data_length.writeUInt32LE(data.length, 0);

// serializing field 1
const field1 = data[0].field1;
const field1_buf = new TextEncoder().encode(field1)
const field1_length = Buffer.allocUnsafe(4);
field1_length.writeUInt32LE(field1_buf.length, 0);

// serializing field 2
const field2 = data[0].field2;
const field2_buf = new TextEncoder().encode(field2)
const field2_length = Buffer.allocUnsafe(4);
field2_length.writeUInt32LE(field2_buf.length, 0);

const instructionBuffer = Buffer.concat([
   ixBuffer,            // namespace+method_name
   data_length,
   field1_length,
   field1_buf,
   field2_length,
   field2_buf,
])

And then redoing the field1 and field2 parts for every element in the array.

2
  • how to serialize fields with integer or float values?
    – Vivek
    Commented Sep 19, 2022 at 6:25
  • It would be better to ask a separate question on exactly what you need help with
    – Jon C
    Commented Sep 19, 2022 at 10:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.