概要
プログラムアカウントは実行可能なsBPFコードを保持します。データアカウントはプログラムが所有する状態を格納します。システムアカウントはSystem Programが所有します。Sysvarsは事前定義されたアドレスでアクセス可能なクラスタ全体の状態を提供します。
executableフィールドがアカウントのカテゴリを決定します:
- プログラムアカウント:
executable=true。実行可能コードを含みます。 - データアカウント:
executable=false。状態またはユーザーデータを格納します。
このコードと可変状態の分離により、プログラムは一度デプロイされ、任意の数のデータアカウントを管理できます。
プログラムアカウント
プログラムアカウントは実行可能コードを格納します。すべてのプログラムアカウントはローダープログラムによって所有されます。プログラムがデプロイされると、ランタイムはそのバイトコードを保持するためのプログラムアカウントを作成します。
プログラムアカウント、その4つのコンポーネント、およびそのローダープログラムの図。
プログラムデータアカウント
loader-v3を使用してデプロイされたプログラム(ローダープログラムを参照)は、独自のdataフィールドに実行可能バイトコードを格納しません。代わりに、そのdataはプログラムコードを含む別のプログラムデータアカウントを指します。(下図を参照してください。)
データを持つプログラムアカウント。データは別のプログラムデータアカウントを指しています
プログラムのデプロイまたはアップグレード中、バッファアカウントはアップロードを一時的にステージングするために使用されます。
次の例では、Token
Programアカウントを取得します。executableフィールドはtrueであり、これがプログラムアカウントであることを確認します。
import { Address, createSolanaRpc } from "@solana/kit";const rpc = createSolanaRpc("https://api.mainnet.solana.com");const programId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address;const accountInfo = await rpc.getAccountInfo(programId, { encoding: "base64" }).send();console.log(accountInfo);
データアカウント
データアカウントには実行可能なコードは含まれません。プログラムで定義された状態を保存します。
プログラム状態アカウント
プログラムはその状態をデータアカウントに保存します。プログラム状態アカウントの作成には2つのステップがあります:
- System Programを呼び出してアカウントを作成します。System Programは所有権を指定されたプログラムに移転します。
- 所有プログラムがアカウントの
dataフィールドをそのinstructionsに従って初期化します。
プログラムアカウントが所有するデータアカウントの図
以下の例では、Token 2022プログラムが所有するToken Mint accountを作成し、取得します。
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が所有し続けるアカウントは、システムアカウントと呼ばれます。新しいアドレスに初めてSOLを送信すると、そのアドレスにSystem Programが所有する新しいアカウントが作成されます。
すべてのウォレットアカウントはシステムアカウントです。トランザクションの手数料支払者はシステムアカウントでなければなりません。なぜなら、System Programが所有するアカウントのみがtransaction feesを支払うことができるからです。
1,000,000 lamportsを含むSystem Programが所有するウォレット
以下の例では、新しいkeypairを生成し、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アカウントは、事前定義されたアドレスに存在する特別なアカウントで、クラスター状態データへの読み取り専用アクセスを提供します。これらは各slotで動的に更新されます。
| Sysvar | アドレス | 目的 |
|---|---|---|
| Clock | SysvarC1ock11111111111111111111111111111111 | 現在のslot、epoch、およびUnixタイムスタンプ |
| EpochSchedule | SysvarEpochSchedu1e111111111111111111111111 | ジェネシスで設定されたepochスケジューリング定数 |
| EpochRewards | SysvarEpochRewards1111111111111111111111111 | epoch報酬の配布状況と進捗状況 |
| Rent | SysvarRent111111111111111111111111111111111 | rentレートと免除しきい値 |
| SlotHashes | SysvarS1otHashes111111111111111111111111111 | slotの親バンクの最新ハッシュ |
| StakeHistory | SysvarStakeHistory1111111111111111111111111 | epoch毎のステークのアクティベーションと非アクティベーション |
| LastRestartSlot | SysvarLastRestartS1ot1111111111111111111111 | 最後のクラスター再起動slot |
| Instructions | Sysvar1nstructions1111111111111111111111111 | 現在のトランザクションのシリアライズされたinstructions |
| SlotHistory | SysvarS1otHistory11111111111111111111111111 | 最後のepoch中に生成されたslotの記録 |
次の例では、Sysvar Clockアカウントを取得してデシリアライズします。
import { createSolanaRpc } from "@solana/kit";import { fetchSysvarClock, SYSVAR_CLOCK_ADDRESS } from "@solana/sysvars";const rpc = createSolanaRpc("https://api.mainnet.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?