29

Is this an account or is it an address? Why do I need it? What problem or use case does it solve? Why can't I just use a regular account instead?

0

5 Answers 5

32

Is this an account or is it an address?

A PDA is an address with special properties. They are 32-byte strings that look like public keys, but don’t have corresponding private keys.

Why do I need it?

There are two main reasons for PDAs;

  1. Store program state
  2. Sign for CPIs

What problem or use case does it solve?

PDA's allow you to create a "hashmap-like" interface for indexing accounts. The seeds used to create the PDAs, function as a way to lookup addresses for a particular piece of data. The seeds can be anything. A pubkey, a string, an array of numbers etc.

Why can't I just use a regular account instead?

You can, but it requires you to explicitly know all the addresses of where data is stored for your program.

Full explanation can be found here


Other resources for understanding PDAs:

https://solanacookbook.com/core-concepts/pdas.html#facts

https://twitter.com/pencilflip/status/1455948263853600768?s=20&t=J2JXCwv395D7MNkX7a9LGw

https://docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses

https://www.anchor-lang.com/docs/pdas

18

Program Derived Addresses (PDAs) are used to allow one program (ProgramB)to assert authority over accounts owned by another (ProgramA).

Since PDAs can't have private keys (both operationally untenable and algorithmically enforced), they have no way to cryptographically sign for an instruction that requires a signature to prove authority. Instead, ProgramB calls ProgramA's instruction via CPI with invoke_signed(), one parameter of which takes "seed" byte strings, which are hashed with ProgramB's Program ID to create a PDA which the runtime then promotes to a transaction signer for the duration of that instruction's execution.

An example use of PDAs is the stake pool program which wraps the native stake program to control delegations to the pool member validators, mint pool tokens in exchange for new delegations and burn pool tokens when a user withdraws.

0
9

I like the other explanations but I thought I'd provide a more theoretical one.

You could think of a Solana Public key as a 32 byte string. However, that wouldn't be the whole picture. In the ed25519 public-key cryptography system used by Solana, not every 32 byte string has a corresponding private key. We call strings that don't have a corresponding private key "off-curve".

All Solana accounts are indexed by a 32 byte string. If you can provide (via signing) a private key for that string, you can freely modify that account. If we can verify that a given 32 byte string is off-curve (which we can), then we can guarantee that nobody can ever modify the account it points to (not that useful yet).

Now I will identify the issue that PDAs were created to solve: anyone can read the contents of any Solana account (including programs, which are just accounts marked as executable). So any private keys held by a program could be read and used by anyone. That would mean programs couldn't control their own state accounts or sign anything.

To solve this problem, we introduce a new "fake" signing mechanism, where we just say that a program can sign for any address P if if 1) P is off-curve and 2) the program can provide a set of seeds such that those seeds hashed together with the program's own address produces P. We call P a Program Derived Address.

This way, programs don't have to hold private keys. And we can be certain that nobody's sitting on a private key for any PDA.

3
  • Really great explanation!
    – OCDev
    Jul 22, 2022 at 2:44
  • OK. That implies, anyone who knows program address and the seeds, can actually modify the accounts owned by the program? program addresses are publicly available data, right? How about the seeds? How secure are they? Feb 5, 2023 at 22:09
  • The seeds are typically also public information. The security mechanism is that the calling program's own address, which can't be controlled, is included in the set of seeds.
    – Ellie High
    Feb 6, 2023 at 23:05
3

A PDA is a Program Derived Address, it's derived from a collection of seeds and a program id.

generating

import {PublicKey} from '@solana/web3'

const [pda,pdaBump] = await PublicKey.findProgramAddress(
   [wallet.publicKey.toBuffer(),Buffer.from(random.toString())], // seeds
   program.programId                                             // programId you're deriving from
);

In this case, I'm using the wallet public key and random string as seeds. you can generate an infinite number of PDAs for a program. but using the same seeds will result in the same PDA address.

usage

  1. A PDA valid transaction signature can only be generated inside the program. this means if a PDA has 5 Sol, only the program can generate a valid transaction that sends the Sol (as if the program has the private key, but it doesn't because PDA are off curve).

  2. A program can have ownership over any account. If that account is owned by a PDA, signing a transaction and using the PDA as a signer will allow you to control that account.

types

A PDA can be of any type, system account to send/receive sol (or sign), token account to send/receive spl tokens, or data account to store data for a program or metadata for an NFT.

example usage (anchor)

pub struct ChangeUsername<'info> {
    #[account(mut,seeds=[payer.key().as_ref()], bump)]
    pub user: Account<'info, User>,
    #[account(mut)]
    pub payer: Signer<'info>,
}

I have a struct that contains a username, and I want each user to be able to change only their username.

We can have the desired effect by creating a PDA (data account in this case) for each user with their public key as seeds. Let's call this User PDA

When a user wants to change their username. We check if the passed PDA is valid (matches a PDA generated using the signer publickey as seeds).

This means if a user2 passes user1 User PDA wishing to change their username. the transaction will fail since the PDA passed doesn't match the PDA generated inside the program using the user2 (signer) public key as seeds

This constraint is checked implicitly in anchor here:

#[account(mut,seeds=[payer.key().as_ref()], bump)]

If the PDA is valid, the transaction goes through and the program will modify the username.

2
  • can data accounts also send/receive SOL and SPL tokens?
    – coco
    Aug 19, 2022 at 22:26
  • You will need a token account for that
    – vicyyn
    Aug 20, 2022 at 9:53
0

You can send money from walletA to an account or walletA to walletB. In Solana every time you send money, someone needs to give permission. A wallet has a user who can give permission to transfer assets.

But what if you need to send money from an account to a wallet? Who is going to give permission? A PDA account is an account that is controlled by the program in order to send funds, not by private keys. Solana has some native programs and those are stored on the chain. They need a way to sign transactions but using a private key is not secure because we have to store this private key on the chain which is public, so everyone can see private keys

Quoting from here:

The secret sauce behind PDAs is that while they look like standard public keys, they don’t actually lie on the ed25519 elliptic curve at all. This means they have no associated private key.

PDAs are derived from a program id and a collection of seeds such as the string "vote_account". This combination of seeds and a program id is then run through a sha256 hash function to see whether or not they generate a public key that lies on the elliptic curve.

It may be helpful to consider that PDAs are not technically created, but rather found. In running our program id and seeds through a hash function, there is a ~50% chance that we actually end up with a valid public key that does lie on the elliptic curve. In this case, we simply add something to fudge our input a little bit and try again. The technical term for this fudge factor is a bump. In Solana, we start with bump = 255 and simply iterate down through bump = 254, bump = 253, etc. until we get an address that is not on the elliptic curve. This may seem rudimentary, but once found it gives us a deterministic way of deriving the same PDA over and over again. This also allows our program to now sign for an account using Solana’s program-signed-accounts

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.