Акаунти
Усі дані в мережі Solana зберігаються в акаунтах. Мережу Solana можна уявити як публічну базу даних з єдиною таблицею Акаунтів. Зв'язок між акаунтом та його адресою подібний до пари ключ-значення, де ключем є адреса, а значенням — акаунт.
Кожен акаунт має однакову базову структуру і може бути знайдений за його адресою.
Діаграма 3 акаунтів та їхніх адрес. Включає визначення структури акаунта.
Адреса акаунта
Адреса акаунта — це унікальний 32-байтовий ідентифікатор, який використовується для пошуку акаунта в блокчейні Solana. Адреси акаунтів часто відображаються як рядки, закодовані в base58. Більшість акаунтів використовують відкритий ключ Ed25519 як свою адресу, але це не обов'язково, оскільки Solana також підтримує програмно похідні адреси.
Акаунт з його адресою відкритого ключа, закодованою в base58
Відкритий ключ
Приклад нижче демонструє, як використовувати Solana SDK для створення keypair. keypair включає:
- Публічний ключ, який служить адресою акаунта
- Приватний ключ, який використовується для підписання транзакцій
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Program Derived Address
Program Derived Address (PDA) - це адреса, яка детерміновано виводиться з використанням ID програми та одного чи кількох необов'язкових вхідних даних (seeds). Приклад нижче демонструє, як використовувати Solana SDK для створення Program Derived Address.
import { Address, getProgramDerivedAddress } from "@solana/kit";const programAddress = "11111111111111111111111111111111" as Address;const seeds = ["helloWorld"];const [pda, bump] = await getProgramDerivedAddress({programAddress,seeds});console.log(`PDA: ${pda}`);console.log(`Bump: ${bump}`);
Структура акаунта
Кожен
Account
має максимальний розмір
10MiB
і містить наступну інформацію:
lamports: Кількість lamports на акаунтіdata: Дані акаунтаowner: ID програми, якій належить акаунтexecutable: Вказує, чи містить акаунт виконуваний бінарний кодrent_epoch: Застаріле поле epoch оренди
pub struct Account {/// lamports in the accountpub lamports: u64,/// data held in this account#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]pub data: Vec<u8>,/// the program that owns this account. If executable, the program that loads this account.pub owner: Pubkey,/// this account's data contains a loaded program (and is now read-only)pub executable: bool,/// the epoch at which this account will next owe rentpub rent_epoch: Epoch,}
Lamports
Баланс акаунта в lamports.
Кожен акаунт повинен мати мінімальний баланс lamports, який називається rent, що дозволяє зберігати його дані в блокчейні. Rent пропорційний розміру акаунта.
Хоча цей баланс називається rent, він працює більше як депозит, оскільки повний баланс можна повернути при закритті рахунку. (Назва "rent" походить від тепер застарілого поля rent epoch.)
(Дивіться формулу мінімального балансу та відповідні константи.)
Дані
Це поле зазвичай називають "даними акаунта". data у цьому полі вважаються
довільними, оскільки можуть містити будь-яку послідовність байтів. Кожна
програма визначає структуру даних, що зберігаються в цьому полі.
- Program accounts: це поле містить або виконуваний код програми, або адресу акаунта даних програми, який зберігає виконуваний код програми.
- Data accounts: це поле зазвичай зберігає дані стану, призначені для читання.
Читання даних із акаунта Solana включає два кроки:
- Отримання акаунта за його адресою
- Десеріалізація поля
dataакаунта з необроблених байтів у відповідну структуру даних, як визначено програмою, якій належить акаунт.
Власник
Це поле містить ідентифікатор програми, яка є власником акаунта.
Кожен акаунт Solana має програму, призначену як його
власника. Власник акаунта — це єдина програма, яка може змінювати data акаунта
або знімати лампорти, як зазначено в інструкціях програми.
(У випадку program account, власником є його програма-завантажувач.)
Виконуваний
Це поле вказує, чи є акаунт program account або data account
- Якщо
true: акаунт є program account - Якщо
false: акаунт є data account
Епоха оренди
Поле rent_epoch застаріле.
Раніше це поле відстежувало, коли акаунту потрібно буде сплатити rent. Однак цей механізм збору rent з того часу застарів.
Типи облікових записів
Існує дві основні категорії облікових записів:
- Програмні облікові записи: Облікові записи, що містять виконуваний код
- Облікові записи даних: Облікові записи, що не містять виконуваного коду
Це розділення коду програми та її стану є ключовою особливістю моделі облікових записів Solana. (Подібно до операційних систем, які зазвичай мають окремі файли для програм та їхніх даних.)
Програмні облікові записи
Кожна програма належить програмі-завантажувачу, яка використовується для розгортання та керування обліковим записом. Коли нова програма розгортається, створюється обліковий запис для зберігання її виконуваного коду. Це називається програмним обліковим записом. (Для простоти можна вважати програмний обліковий запис самою програмою.)
На діаграмі нижче ви можете побачити, як програма-завантажувач використовується
для розгортання програмного облікового запису. Поле data програмного
облікового запису містить виконуваний код програми.
Діаграма програмного облікового запису, його 4 компонентів та програми-завантажувача.
Облікові записи даних програми
Програми, розгорнуті за допомогою loader-v3, не містять програмного коду в полі
data. Натомість, їхнє поле data вказує на окремий обліковий запис даних
програми, який містить код програми. (Див. діаграму нижче.)
Програмний обліковий запис з даними. Дані вказують на окремий обліковий запис даних програми
Під час розгортання або оновлення програми буферні облікові записи використовуються для тимчасового розміщення завантаження.
У прикладі нижче отримується обліковий запис Token Program. Зверніть увагу, що
поле executable встановлено як true, що вказує на те, що обліковий запис є
програмою.
import { Address, createSolanaRpc } from "@solana/kit";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const programId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address;const accountInfo = await rpc.getAccountInfo(programId, { encoding: "base64" }).send();console.log(accountInfo);
Акаунти даних
Акаунти даних не містять виконуваного коду. Натомість вони зберігають інформацію.
Акаунт стану програми
Програми використовують акаунти даних для підтримки свого стану. Для цього вони спочатку повинні створити новий акаунт даних. Процес створення акаунта стану програми часто абстрагується, але корисно розуміти основний процес.
Щоб керувати своїм станом, нова програма повинна:
- Викликати System Program для створення акаунта. (System Program потім передає право власності новій програмі.)
- Ініціалізувати дані акаунта, як визначено її інструкціями.
Діаграма акаунта даних, яким володіє акаунт програми
У наведеному нижче прикладі створюється та отримується акаунт Token Mint, яким володіє програма Token 2022.
import {airdropFactory,appendTransactionMessageInstructions,createSolanaRpc,createSolanaRpcSubscriptions,createTransactionMessage,generateKeyPairSigner,getSignatureFromTransaction,lamports,pipe,sendAndConfirmTransactionFactory,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,signTransactionMessageWithSigners} from "@solana/kit";import { getCreateAccountInstruction } from "@solana-program/system";import {getInitializeMintInstruction,getMintSize,TOKEN_2022_PROGRAM_ADDRESS,fetchMint} from "@solana-program/token-2022";// Create Connection, local validator in this exampleconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate keypairs for fee payerconst feePayer = await generateKeyPairSigner();// Fund fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: feePayer.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});// Generate keypair to use as address of mintconst mint = await generateKeyPairSigner();// Get default mint account size (in bytes), no extensions enabledconst space = BigInt(getMintSize());// Get minimum balance for rent exemptionconst rent = await rpc.getMinimumBalanceForRentExemption(space).send();// Instruction to create new account for mint (token 2022 program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token 2022 programconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 9,mintAuthority: feePayer.address});const instructions = [createAccountInstruction, initializeMintInstruction];// Get latest blockhash to include in transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// Create transaction messageconst transactionMessage = pipe(createTransactionMessage({ version: 0 }), // Create transaction message(tx) => setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash(tx) => appendTransactionMessageInstructions(instructions, tx) // Append instructions);// Sign transaction message with required signers (fee payer and mint keypair)const signedTransaction =await signTransactionMessageWithSigners(transactionMessage);// Send and confirm transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });// Get transaction signatureconst transactionSignature = getSignatureFromTransaction(signedTransaction);console.log("Mint Address:", mint.address);console.log("Transaction Signature:", transactionSignature);const accountInfo = await rpc.getAccountInfo(mint.address).send();console.log(accountInfo);const mintAccount = await fetchMint(rpc, mint.address);console.log(mintAccount);
Системні акаунти
Не всі акаунти отримують нового власника після створення System Program. Акаунти, якими володіє System Program, називаються системними акаунтами. Усі гаманці є системними акаунтами, що дозволяє їм сплачувати комісії за транзакції.
Гаманець, яким володіє System Program, що містить 1 000 000 лампортів
Коли SOL вперше надсилається на нову адресу, на цій адресі створюється акаунт, яким володіє System Program.
У наведеному нижче прикладі генерується нова пара ключів і фінансується SOL.
Після запуску коду ви можете побачити, що адреса власника акаунта owner є
11111111111111111111111111111111
(System Program).
import {airdropFactory,createSolanaRpc,createSolanaRpcSubscriptions,generateKeyPairSigner,lamports} from "@solana/kit";// Create a connection to Solana clusterconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate a new keypairconst keypair = await generateKeyPairSigner();console.log(`Public Key: ${keypair.address}`);// Funding an address with SOL automatically creates an accountconst signature = await airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: keypair.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});const accountInfo = await rpc.getAccountInfo(keypair.address).send();console.log(accountInfo);
Акаунти Sysvar
Облікові записи Sysvar існують за попередньо визначеними адресами та надають доступ до даних стану кластера. Вони динамічно оновлюються даними про мережевий кластер. Перегляньте повний список облікових записів Sysvar.
У наведеному нижче прикладі отримуються та десеріалізуються дані з облікового запису Sysvar Clock.
import { createSolanaRpc } from "@solana/kit";import { fetchSysvarClock, SYSVAR_CLOCK_ADDRESS } from "@solana/sysvars";const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");const accountInfo = await rpc.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" }).send();console.log(accountInfo);// Automatically fetch and deserialize the account dataconst clock = await fetchSysvarClock(rpc);console.log(clock);
Is this page helpful?