I am go through the solana course and I am not understand that basics of writing solana native programs. Why do we need to pass to the functions some AccountInfo slice? Where this adressess should come from? I am focus just only on Rust code and don't try to write typescript rust frontend, maybe that the reason? For me it looks very strange, because we pass some Accounts to the function, then in code find some pda and verify, that pda we find with the account that was passed into the function. Why we can't just use that key?
1 Answer
A smart-contract execution environment depends on all the state that it needs being loaded unto it at runtime. Different chains have different ways of providing a program with the data that it needs.
As a prelude it's important to note that everything on Solana is an account. Even a program is just an account that's marked as executable and stores instruction data that can be executed.
The simple answer to your question is that programs on Solana are stateless
. While a stateful program model stores all the objects/state that a program needs in the same account as the program data itself, a stateless program(like Solana) doesn't.
Instead, on Solana, each unit of a program's state is stored in its distinct accounts(think of a unit
as a single instance of a particular type/struct you define for your program).
In a stateful model loading just the program account would be enough to grant runtime access to all the state you need since they're stored together with it. However since a Solana program's state is stored in its own account, each of the accounts needed for a particular instruction have to be loaded separately, as the program needs to access its data somehow.
This introduces the need for extra careful checks that a particular account being loaded is actually the valid one that the program expects.
For instance if your program's global state is initialized in an account with key Hc73...8xbi
, it's required that you check that the account being passed in as the global state in subsequent instruction is of the key Hc73...
. Otherwise anyone could pass in the wrong account info and cause unwanted behaviour or hacks in your program.
TLDR:
- For smart-contract execution, state has to be loaded unto the execution environment.
- Stateful models like Ethereum store all their state with the program; loading just the program account is enough to provide all the state it needs, abstracting away these worries.
- Solana programs are stateless and store state separate from the program account; each "state" has to be loaded from its own distinct account.
- An on-chain program can only access data loaded unto it before runtime execution. A pubkey is just an 32-byte identifier and does not contain actual data.
- Since pubkeys are unique, they are used on-chain to verify that the account supplying the data is the valid one you expect, and not some incorrect or malicious one.
-
Need to clarify yet one moment with PDA. What happens here
let (mint_pda, _mint_bump) = Pubkey::find_program_address(&[b"token_mint"], program_id); let (mint_auth_pda, mint_auth_bump) = Pubkey::find_program_address(&[b"token_auth"], program_id); if *token_mint.key != mint_pda { return Err(StudentIntroError::InvalidPDA.into()); } if *mint_auth.key != mint_auth_pda { return Err(StudentIntroError::InvalidPDA.into()); }
. We find PDA off the eliptic curve, but then we can compare it with another account.– GilssonCommented Apr 26, 2023 at 20:33 -
This is a security check that the account we're loading our accountinfo from is valid. We know the seeds of the mint account and so we can always derive its key on-chain. We check that the key of the account passed in as the mint matches that derived key, to guard against a client passing in the wrong account and compromising the program– AdemolaCommented Apr 27, 2023 at 19:19