1

I want to create a hash-table using PDAs with seeds including: i) table-name ii) a u32 integer as key

I tried this:

#[account(
    init,
    payer=user,
    space = 8 + 1 + 32 + 8 + 8,
    seeds = [b"users_table", a_u32_int.as_ref()],
    bump
)]
pub users_table: Account<'info, UsersTable>,

But here, I was not able to use u32 integer as reference.

Github-copilor suggested this seeds = [b"users_table", 0u32.to_le_bytes().as_ref()], but I am not sure what .to_le_bytes() mean in rust

Also I don't know how I can generate a PDA-address for this in frontend to send as parameter for anchor program's accounts as await PublicKey.findProgramAddress() does not support numbers

2 Answers 2

2

We can create hashmaps and nested hashmaps this way

On contract-side:

#[account(mut)]
pub user: Signer<'info>,

// data for seeds from counter-account can be read from other pda-account 
// this is helpful when you want to track and store size of hash-map on-chain
#[account(
        seeds = [b"counter"],
        bump = counter.bump,
    )]
pub counter: Account<'info, CounterInfo>,


#[account(
    init,
    payer=user,
    space = 8 + 1 + 32 + 8 + 8,
    seeds = [format!("users_table-{}-{}", counter.index1, counter.index2).as_ref()],
    bump,
)]
pub users_table: Account<'info, UsersTable>,

On client side, we can get pda-address as:

const num1 = 3, num2 = 15
const [usersTablePDA, _] = await PublicKey.findProgramAddress(
  [
    anchor.utils.bytes.utf8.encode(`users_table-${num1}-${num2}`),
  ],
  program.programId
)

I am beginner at rust and solana, suggestion from a experienced developer about code safety will be helpful

2

await PublicKey.findProgramAddress() expects a Buffer or Uint8Array, and the program's address.

u8

So you could perhaps do (i have not tested it):

const yourIndex = a; // a u8 number ranging from 0 and 255
const pda = await PublicKey.findProgramAddress([utf8.encode('users_table'), [yourIndex]], programId)

This limits you to the range of a Uint8 so that might not be good enough.

On the Rust side you'd have to store this index in another account and get it something like:

seeds = [b"users_table", &[other_account.your_index_u8]],

u32

If you like to use u32, like in your example, you could store many more indices (namely 4 bytes of memory).

In that case it would look something like

const yourIndex = new BN(a);
const byteArray = yourIndex.toArray('le', 4);
const pda = await PublicKey.findProgramAddress([utf8.encode('users_table'), byteArray], programId)

And on the Rust side:

seeds = [b"users_table", other_account.your_index_u32.to_le_bytes().as_ref()]],

FYI: .to_le_bytes() for u32

Return the memory representation of this integer as a byte array in little-endian byte order.

This means it will convert the integer into 4 x u8 bytes, to represent it.

2
  • const yourIndex = a; // UInt8Array of length 4, I does not find one-line syntax to convert a number to UintArray of lengh 4 in javascript, do you know any ? Commented Oct 12, 2022 at 15:25
  • @MaheshGhamaand you should use the BN() module for that. const yourIndex = new BN(a); const byteArray = yourIndex.toArray('le', 4); Note the le Endianness should match the order that you use on the contract side. So to_le_bytes() ! Have updated my answer. Commented Oct 13, 2022 at 9:29

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.