Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should account struct definition be treated differently than other idl types? #1971

Closed
Arrowana opened this issue Jun 14, 2022 · 3 comments
Closed
Labels
bug Something isn't working idl related to the IDL, either program or client side

Comments

@Arrowana
Copy link
Contributor

Arrowana commented Jun 14, 2022

Problem:
If the struct of an account is used in another account field (odd) or in an event, it breaks all assumptions because the event cannot see the account struct under "types".

Use case:
Putting an account struct into an anchor event field

Proposed solution:
account struct are types and "accounts" in the idl account entry can point to an IdlType::Defined(String)

Other solution: "accounts" items contain name only and we implicitly expect the corresponding type to exist

Example tests/chat chat.json with the change #1970

  "accounts": [
    {
      "name": "User",
      "type": {
        "defined": "User"
      }
    },
    {
      "name": "ChatRoom",
      "type": {
        "defined": "ChatRoom"
      }
    }
  ],
  "types": [
    {
      "name": "User",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "name",
            "type": "string"
          },
          {
            "name": "authority",
            "type": "publicKey"
          },
          {
            "name": "bump",
            "type": "u8"
          }
        ]
      }
    },

example using the second solution, which woud break backward compatibility :s

  "accounts": [
    {
      "name": "User"
    },
    {
      "name": "ChatRoom"
    }
  ],
  "types": [
    {
      "name": "User",
      "type": {
        "kind": "struct",
        "fields": [
          {
            "name": "name",
            "type": "string"
          },
          {
            "name": "authority",
            "type": "publicKey"
          },
          {
            "name": "bump",
            "type": "u8"
          }
        ]
      }
    },

A light exchange on discord about this https://discord.com/channels/889577356681945098/891724485177245717/985920160294662164

@CanardMandarin
Copy link
Contributor

CanardMandarin commented Dec 31, 2022

I encountered this particular edge case.
Let's say I need to keep an offchain history of the state of an account instruction per instruction.

Small example:

#[account]
pub struct Ledger {
    pub authority: Pubkey,
    pub is_active: bool,
    // ... more stuff
}

pub fn update_ledger(
    ctx: Context<UpdateLedger>,
    is_active: bool,
) -> Result<()> {
   ctx.accounts.ledger.is_active = is_active;
}

Instead of parsing the data of every instruction called and replicating the logic of the program on a backend.
I was tempted to take advantage of anchor events and just output the modified account in an event.

#[event]
pub struct UpdateLedgerEvent {
    pub timestamp: u64,
    pub signer: Pubkey,
    pub ledger: Ledger,
}

pub fn update_ledger(
    ctx: Context<UpdateLedger>,
    is_active: bool,
) -> Result<()> {
   ctx.accounts.ledger.is_active = is_active;
    emit!(UpdateLedgerEvent {....});
}

It allows me to just parse the event and push the new state directly into a database without rewriting the logic of my program.
In a perfect world, I would setup a RPC with the geyser plugin and subscribe to accounts updates. But it is a bit too much in my case.

@CanardMandarin
Copy link
Contributor

I ended up doing this:

#[account]
pub struct Ledger {
    pub authority: Pubkey,
    pub is_active: bool,
    // ... more stuff
}

// duplicating the struct of my account so it will create the type in the IDL.
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct LedgerStateEvent {
    pub authority: Pubkey,
    pub is_active: bool,
    // ... more stuff
}

impl From<Ledger> for LedgerStateEvent {
    fn from(b: Ledger) -> LedgerStateEvent {
        unsafe { std::mem::transmute(b) }
    }
}

#[event]
pub struct UpdateLedgerEvent {
    pub timestamp: u64,
    pub signer: Pubkey,
    pub ledger: LedgerStateEvent,
}

@acheroncrypto acheroncrypto mentioned this issue Feb 25, 2024
@acheroncrypto acheroncrypto added bug Something isn't working idl related to the IDL, either program or client side labels Mar 10, 2024
@acheroncrypto
Copy link
Collaborator

Fixed by #2824.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working idl related to the IDL, either program or client side
Projects
None yet
Development

No branches or pull requests

3 participants