アカウント
Solanaネットワーク上のすべてのデータはアカウントに保存されています。Solanaネットワークを単一のアカウントテーブルを持つ公開データベースと考えることができます。アカウントとそのアドレスの関係は、キーがアドレスで値がアカウントであるキーと値のペアに似ています。
各アカウントは同じ基本的な構造を持ち、そのアドレスを使用して見つけることができます。
3つのアカウントとそのアドレスの図。アカウント構造の定義を含む。
アカウントアドレス
アカウントのアドレスは、Solanaブロックチェーン上でアカウントを特定するための32バイトの一意のIDです。アカウントアドレスはよくbase58でエンコードされた文字列として表示されます。ほとんどのアカウントはアドレスとしてEd25519公開鍵を使用していますが、SolanaはProgram Derived Addressもサポートしているため、これは必須ではありません。
base58でエンコードされた公開鍵アドレスを持つアカウント
公開鍵
以下の例は、Solana SDKを使用してkeypairを作成する方法を示しています。
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Console
Click to execute the code.
Program Derived Address
Program Derived Address(PDA)は、プログラムIDと1つ以上のオプション入力(シード)を使用して決定論的に導出されるアドレスです。以下の例は、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}`);
Console
Click to execute the code.
アカウント構造
すべてのAccountは最大サイズが10MiBで、以下の情報を含んでいます:
lamports: アカウント内のlamportsの数data: アカウントのデータowner: アカウントを所有するプログラムのIDexecutable: アカウントが実行可能なバイナリを含むかどうかを示すrent_epoch: 非推奨のrent epochフィールド
Account
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
アカウントの残高(lamport単位)。
すべてのアカウントは、rentと呼ばれる最低限のlamport残高を持つ必要があります。これによりデータをチェーン上に保存することができます。rentはアカウントのサイズに比例します。
この残高は「rent」と呼ばれていますが、実際には預け金のように機能します。アカウントが閉鎖されると全額が回収できるためです。(「rent」という名前は、現在は非推奨となっているrent epochフィールドに由来しています。)
データ
このフィールドは一般的に「アカウントデータ」と呼ばれています。このフィールドのdataは任意のバイト列を含むことができるため、任意と見なされます。各プログラムがこのフィールドに格納されるデータの構造を定義します。
- Program accounts: このフィールドには、実行可能なプログラムコードか、実行可能なプログラムコードを格納するプログラムデータアカウントのアドレスが含まれています。
- データアカウント: このフィールドには一般的に、読み取り用の状態データが格納されています。
Solanaアカウントからデータを読み取るには、次の2つのステップが必要です:
- アドレスを使用してアカウントを取得する
- プログラムが定義したデータ構造に従って、アカウントの
dataフィールドを生のバイトから適切なデータ構造にデシリアライズする
オーナー
実行可能フラグ
このフィールドは、アカウントがprogram accountかデータアカウントかを示します
trueの場合:アカウントはprogram accountですfalseの場合:アカウントはデータアカウントです
Rent epoch
rent_epochフィールドは非推奨です。
過去には、このフィールドはアカウントがrentを支払う必要がある時期を追跡していました。しかし、このrent徴収メカニズムはその後非推奨となりました。
アカウントの種類
アカウントは基本的に2つのカテゴリに分類されます:
- Program accounts:実行可能なコードを含むアカウント
- データアカウント:実行可能なコードを含まないアカウント
この分離により、プログラムの実行可能コードとその状態は別々のアカウントに格納されます。(オペレーティングシステムが通常、プログラムとそのデータを別々のファイルに持つのと同様です。)
Program accounts
すべてのプログラムはローダープログラムによって所有されており、このローダープログラムはアカウントのデプロイと管理に使用されます。新しいプログラムがデプロイされると、その実行可能コードを格納するためのアカウントが作成されます。これをprogram accountと呼びます。(簡単に言えば、program accountをプログラム自体と考えることができます。)
下の図では、ローダープログラムがprogram
accountをデプロイするために使用されているのがわかります。program
accountの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);
Console
Click to execute the code.
データアカウント
データアカウントは実行可能なコードを含みません。代わりに、情報を保存します。
プログラム状態アカウント
プログラムはデータアカウントを使用して状態を維持します。そのためには、まず新しいデータアカウントを作成する必要があります。プログラム状態アカウントの作成プロセスはしばしば抽象化されていますが、基本的なプロセスを理解することは役立ちます。
状態を管理するために、新しいプログラムは以下を行う必要があります:
- System Programを呼び出してアカウントを作成します。(System Programはその後、所有権を新しいプログラムに転送します。)
- instructionsで定義されているように、アカウントデータを初期化します。
プログラムアカウントによって所有されるデータアカウントの図
以下の例では、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);
Console
Click to execute the code.
システムアカウント
System Programによって作成されたすべてのアカウントが新しい所有者に割り当てられるわけではありません。System Programが所有するアカウントはシステムアカウントと呼ばれます。すべてのウォレットアカウントはシステムアカウントであり、これにより取引手数料を支払うことができます。
System Programが所有する1,000,000ラムポートを含むウォレット
SOLが初めて新しいアドレスに送信されると、そのアドレスに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);
Console
Click to execute the code.
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);
Console
Click to execute the code.
Is this page helpful?