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

Feature Request: Automatic client-side derivation of PDAs #1004

Closed
mschneider opened this issue Nov 12, 2021 · 7 comments · Fixed by #1331
Closed

Feature Request: Automatic client-side derivation of PDAs #1004

mschneider opened this issue Nov 12, 2021 · 7 comments · Fixed by #1331
Assignees

Comments

@mschneider
Copy link
Contributor

Right now the IDL does not allow to communicate PDA derivation paths. Hence an anchor user needs to replicate the derivation logic both on the client as well as on the program side. It's a common source of errors for sure. Here's an example of such a derivation helper in one of the anchor programs I recently wrote.

https://github.com/mschneider/assembly/blob/2a820887f7efd9033a88fe19117d41895bdfe660/lib/index.ts#L290

@mschneider mschneider changed the title Feature Request: Derivation of PDAs Feature Request: Automatic client-side derivation of PDAs Nov 12, 2021
@armaniferrante
Copy link
Member

Sounds like we need to have a way to declaratively specify PDA seeds that are a function of either constants, or other accounts in a given context. This has come up a several times so there's definitely demand for this feature.

Any suggestions for what this API would look like?

@cyphersnake
Copy link
Contributor

cyphersnake commented Nov 14, 2021

Forgive me for getting in, but I also really want this feature and am ready to help with the implementation 😅

  • For the Rust client, all derived fields can be made non-public and initialized from the rest according to the same rules as in the contract code. This implementation does not sound difficult since the description of the account contains all the necessary information. The only thing is that the arguments (which can also be the source of seeds) are not a public type, since their definition is duplicated with #[instruction(...)].But if we extend the API so that this attribute will also take the name of the functions (#[from_instruction(public_func)] and use the type generated for this function), then it will be possible to define a list of accounts based on the entire context of the call.
let data = my_program::instruction::Method {
    ...
};
let acc = my_program:accounts::MethodAccountsBuilder::default()
    .instruction(&data)
    .account_one(pubkey)
    .build()?;
// Or
let acc = my_program:accounts::MethodAccounts {
    from_instruction: &data,
    account_one: pubkey
};
// And we do final transformation at the `to_account_metas` level. 
// The `Builder` option is a little cleaner, but the completeness
// check happens at runtime, which is always frustrating.
  • For other clients, automatically define accounts with simple seeds: constants, arguments, and keys from other accounts. This information can be directly contained in the IDL.
{
    "name": "pda_account",
    "isMut": true,
    "isSigner": false,
    "seeds": [
        {
            "type": "const",
            "name": "MYSEED",
            "_comment": "The only thing that needs to be clarified is that there are bytes and string constants that are converted to these bytes."
        },
       {
            "type": "string",
            "name": "STRING_FOR_UTF8_ENCODE"
        },
        {
            "type": "account",
            "name": "source_of_seed",
            "_comment": "Here we take the key from this account"
        },
        {
            "type": "arg",
            "name": "source_of_seed",
            "_comment": "And here we take the argument directly, but limit the possible types for this feature"
        }
    ]
}

@mschneider
Copy link
Contributor Author

mschneider commented Nov 14, 2021

looks good, probably adding a few more types will help:

  1. constant - to embed a string constant
  2. fields on loaded account - sometimes a part of the seed is saved in a field on the account and not just the pubkey of it

@cyphersnake
Copy link
Contributor

cyphersnake commented Nov 14, 2021

  1. Yes, I forgot to add example with constants, thanks!
  2. How do you see it?
    • The API that set pubkey by the account type is not very optimal, since you may need one field, but you need to request hole account. You can have it cached, it can be hidden in a contract in a method like, etc. One field (or two) information can be transferred without direct account information
    • The request for the required account in the background from chain does not look very optimal in terms of speed
    • Adding dependency information to the data type looks good, but I can't imagine how to define the account automatically in that case. At least for the first version of this feature.
    • I would be glad to be convinced! 🙃

@mschneider
Copy link
Contributor Author

a) on-chain it's probably ok and all easy as the account anyways was loaded by the run-time
b) off-chain works if you let the user provide the parsed account data on every request, we can make the following assumptions:

  1. the value of the field never changes - it is set when initializing the account - any change would cause an address change after all
  2. this type of seeding would be used to model 1:n relationships. this means the account is always fetched by the client before making a request via getProgramAccounts with a filter, so part of a larger collection of accounts.

@armaniferrante
Copy link
Member

armaniferrante commented Jan 24, 2022

Note that although #1331 completes this task, we really need #1039 #1367 as well to have a great client side experience, i.e., so that we can avoid passing in bumps from the client altogether.

@armaniferrante
Copy link
Member

The first version of this feature is gated by a CLI feature flag in the Anchor.toml.

[features]
seeds = true

When this is enabled, seeds will be parsed into the IDL and automatically used to generate PDAs in the new typescript builder API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants