coral-xyz / anchor

⚓ Solana Sealevel Framework
https://anchor-lang.com
Apache License 2.0
3.51k stars 1.3k forks source link

Suggestion for IDL format #3092

Open 0xk2 opened 1 month ago

0xk2 commented 1 month ago

Motivation

The idl is missing some of the information from the code. For example in this image: idl problem The relation among the Bag account and Community & MemberInfo account is not shown in the idl while in fact sometimes they are attached to each other.

#[account]
#[derive(InitSpace)]
pub struct Bag {
    pub community: Pubkey,
    pub member: Pubkey,
    pub amount: u64,
    pub decay_at: u64,
    pub created_at: u64,
}

and the

#[derive(Accounts)]
pub struct TransferCtx<'info> {
...
        /// CHECK: already check on bag
    pub member: AccountInfo<'info>, // receiver
....
    #[account(init, payer = sender, 
        seeds=[Bag::SEED, receiver_info.key().as_ref(), &receiver_info.max.to_le_bytes()], bump, 
        space=8 + Bag::INIT_SPACE, owner = phanuel_program.key.clone())]
    pub bag: Account<'info, Bag>,
    pub community_account: Account<'info, CommunityAccount>,
...
}

and in the instruction code:

 ctx.accounts.bag.member = *ctx.accounts.member.key;
 ctx.accounts.bag.community = ctx.accounts.community_account.key();

Why stating this relation matters?

While data in blockchain is public, but without easily accessible mean to understand the data structure then the benefit of publicing data become less. Stating this relation make it much easier to visualise the relations among PDAs, how the program works and potentially enable AI to automatically build UI for on-chain program.

Solution

Enable developers to add ref in the idl. The reference can be a account name within the current idl or another program's account type.

Reference within the idl

Example for the data type:

// idl
{
 "types": [
  ///
  {
   "name": "Bag",
   "fields": [
     {
      "name": "community",
      "type": "pubkey",
      "ref": "CommunityAccount"
     }
   ]
  }
  ///
 ]
}

Reference outside of the idl

Example for the data type:

// idl
{
 "types": [
  ///
  {
   "name": "Bag",
   "fields": [
     {
      "name": "community",
      "type": "pubkey",
      "ref": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s::CommunityAccount"
     }
   ]
  }
  ///
 ]
}

Discussion

acheroncrypto commented 1 month ago

This was something I was going to add to the new IDL spec, but then decided it didn't add enough value due to the fact that an account's type can be inferred from its on-chain data and its discriminator.

While data in blockchain is public, but without easily accessible mean to understand the data structure then the benefit of publicing data become less.

When you have an instruction and access to an RPC endpoint, the IDL stores enough information to derive the account's type. We strive to avoid storing anything that can be derived by clients to keep the IDL as small as possible.

Stating this relation make it much easier to visualise the relations among PDAs, how the program works and potentially enable AI to automatically build UI for on-chain program.

Changing the IDL spec in order to "potentially enable AI to automatically build UI for on-chain program" doesn't make sense to me.

0xk2 commented 1 month ago

This was something I was going to add to the new IDL spec, but then decided it didn't add enough value due to the fact that an account's type can be inferred from its on-chain data and its discriminator.

While data in blockchain is public, but without easily accessible mean to understand the data structure then the benefit of publicing data become less.

When you have an instruction and access to an RPC endpoint, the IDL stores enough information to derive the account's type. We strive to avoid storing anything that can be derived by clients to keep the IDL as small as possible.

Stating this relation make it much easier to visualise the relations among PDAs, how the program works and potentially enable AI to automatically build UI for on-chain program.

Changing the IDL spec in order to "potentially enable AI to automatically build UI for on-chain program" doesn't make sense to me.

The ref field I want to add reside INSIDE the types.

// idl
{
 "types": [
  ///
  {
   "name": "Bag",
   "fields": [
     {
      "name": "community",
      "type": "pubkey",
      "ref": "CommunityAccount" // NOT EXISTING in current format
     }
     ... other fields ...
   ]
  }
  ///
 ]
}

In the current format, there is no way I can refer that the community field in the Bag account is a CommunityAccount, even with the instruction. The only way is actually read the code which is not feasible when devs are not revealing it.

Using RDBMS as analogy, the existing idl only store the column type, without storing the foreign key ~ in my case, the Bag table refer to the CommunityAccount table using the community column as foreign key. You can take a look at my toy site here and look at the bottom of the site & click on each of the account name, where I treat each account as a table.

I believe this improvement in idl format will provide much more info for UX developer to render information from a PDA, this is helpful to blockchain explorer service, or someone developing an AI to automatically analyse a PDA / Program and tell users what is going on. For the concern on additional space it will take; a local ref will cost 8 bytes since it is anchor internal discriminator; a global ref might be 32+8 bytes, 32 bytes for programId ad 8 bytes for local discriminator of that program.

Thanks!