Solana Hesap Modeli

Solana'da, tüm veriler "hesaplar" olarak adlandırılan yapılarda saklanır. Solana'daki verileri, tek bir "Hesaplar" tablosuna sahip halka açık bir veritabanı olarak düşünebilirsiniz ve bu tablodaki her giriş bir "hesaptır". Her Solana hesabı aynı temel Hesap türünü paylaşır.

HesaplarHesaplar

Önemli Noktalar

  • Hesaplar, yürütülebilir program kodunu veya program durumunu içeren en fazla 10MiB veri depolayabilir.
  • Hesaplar, depolanan veri miktarıyla orantılı olarak lamport (SOL) cinsinden bir rent depoziti gerektirir ve hesabı kapattığınızda bu depozitoyu tamamen geri alabilirsiniz.
  • Her hesabın bir program sahibi vardır. Bir hesabın verilerini değiştirebilen veya lamport bakiyesini düşürebilen yalnızca hesabın sahibi olan programdır. Ancak herkes bakiyeyi artırabilir.
  • Sysvar hesapları, ağ kümesi durumunu depolayan özel hesaplardır.
  • Program account'ları, akıllı sözleşmelerin yürütülebilir kodunu depolar.
  • Veri hesapları, program durumunu depolamak ve yönetmek için programlar tarafından oluşturulur.

Hesap

Solana'daki her hesabın, genellikle base58 kodlu bir dize olarak gösterilen benzersiz bir 32 baytlık adresi vardır (örneğin, vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg).

Hesap ile adresi arasındaki ilişki, adresin hesabın zincir üzerindeki ilgili verilerini bulmak için anahtar olduğu bir anahtar-değer çifti gibi çalışır. Hesap adresi, "Hesaplar" tablosundaki her giriş için "benzersiz kimlik" görevi görür.

Hesap AdresiHesap Adresi

Çoğu Solana hesabı, adres olarak bir Ed25519 açık anahtarı kullanır.

import { generateKeyPairSigner } from "@solana/kit";
// Kit does not enable extractable private keys
const keypairSigner = await generateKeyPairSigner();
console.log(keypairSigner);
Console
Click to execute the code.

Açık anahtarlar yaygın olarak hesap adresleri olarak kullanılırken, Solana aynı zamanda Program Derived Addresses (PDA'lar) adı verilen bir özelliği de destekler. PDA'lar, bir program kimliğinden ve isteğe bağlı girdilerden (seed) deterministik olarak türetebileceğiniz özel adreslerdir.

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.

Hesap Türü

Hesaplar maksimum 10MiB boyutunda olabilir ve Solana'daki her hesap aynı temel Account türünü paylaşır.

Hesap TürüHesap Türü

Solana'daki her hesabın aşağıdaki alanları vardır:

  • data: Bir hesap için rastgele verileri depolayan bir bayt dizisi. Yürütülebilir olmayan hesaplar için, bu genellikle okunması amaçlanan durumu depolar. Program hesapları (akıllı sözleşmeler) için, bu alan yürütülebilir program kodunu içerir. Veri alanı yaygın olarak "hesap verisi" olarak adlandırılır.
  • executable: Bu bayrak, bir hesabın program olup olmadığını gösterir.
  • lamports: Hesabın lamport cinsinden bakiyesi, SOL'un en küçük birimi (1 SOL = 1 milyar lamport).
  • owner: Bu hesaba sahip olan programın program kimliği (açık anahtar). Yalnızca sahibi olan program, hesabın verilerini değiştirebilir veya lamport bakiyesini düşürebilir.
  • rent_epoch: Solana'nın hesaplardan periyodik olarak lamport düştüğü bir mekanizmaya sahip olduğu zamanlardan kalma eski bir alan. Bu alan hala Account türünde mevcut olsa da, rent toplama kullanımdan kaldırıldığından artık kullanılmamaktadır.
Base Account Type
pub struct Account {
/// lamports in the account
pub 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 rent
pub rent_epoch: Epoch,
}
import {
airdropFactory,
createSolanaRpc,
createSolanaRpcSubscriptions,
generateKeyPairSigner,
lamports
} from "@solana/kit";
// Create a connection to Solana cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate a new keypair
const keypair = await generateKeyPairSigner();
console.log(`Public Key: ${keypair.address}`);
// Funding an address with SOL automatically creates an account
const 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.

Rent

Zincir üzerinde veri depolamak için, hesapların ayrıca hesapta depolanan veri miktarıyla (bayt cinsinden) orantılı bir lamport (SOL) bakiyesi tutması gerekir. Bu bakiyeye "rent" denir, ancak daha çok bir depozito gibi çalışır çünkü bir hesabı kapattığınızda tam tutarı geri alabilirsiniz. Hesaplamayı burada bu sabitler kullanılarak bulabilirsiniz.

"Rent" terimi, rent eşiğinin altında kalan hesaplardan düzenli olarak lamport düşen kullanımdan kaldırılmış bir mekanizmadan gelmektedir. Bu mekanizma artık aktif değildir.

Program Sahibi

Solana'da, "akıllı sözleşmeler" programlar olarak adlandırılır. Program sahipliği, Solana Hesap Modeli'nin önemli bir parçasıdır. Her hesabın belirlenmiş bir program sahibi vardır. Yalnızca sahibi olan program:

  • Hesabın data alanını değiştirebilir
  • Hesabın bakiyesinden lamport düşebilir

System Program

Varsayılan olarak, tüm yeni hesaplar System Program tarafından sahiplenilir. System Program birkaç önemli işlev yapar:

  • Yeni Hesap Oluşturma: Yalnızca System Program yeni hesaplar oluşturabilir.
  • Alan Tahsisi: Her hesabın veri alanı için bayt kapasitesini belirler.
  • Program Sahipliğini Transfer Etme / Atama: System Program bir hesap oluşturduktan sonra, belirlenmiş program sahibini farklı bir program account'a yeniden atayabilir. Özel programların System Program tarafından oluşturulan yeni hesapların sahipliğini alması bu şekilde gerçekleşir.

Solana'daki tüm "cüzdan" hesapları, sadece System Program tarafından sahiplenilen hesaplardır. Bu hesaplardaki lamport bakiyesi, cüzdan tarafından sahip olunan SOL miktarını gösterir. Yalnızca System Program tarafından sahiplenilen hesaplar işlem ücretlerini ödeyebilir.

Sistem HesabıSistem Hesabı

Sysvar Hesapları

Sysvar hesapları, küme durum verilerine erişim sağlayan önceden tanımlanmış adreslerdeki özel hesaplardır. Bu hesaplar, ağ kümesi hakkındaki verilerle dinamik olarak güncellenir. Sysvar Hesaplarının tam listesini burada bulabilirsiniz.

import { Address, createSolanaRpc } from "@solana/kit";
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
const SYSVAR_CLOCK_ADDRESS =
"SysvarC1ock11111111111111111111111111111111" as Address;
const accountInfo = await rpc
.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" })
.send();
console.log(accountInfo);
Console
Click to execute the code.

Program Account

Bir Solana programı dağıtmak, çalıştırılabilir bir program hesabı oluşturur. Program hesabı, programın çalıştırılabilir kodunu saklar.

Program hesapları bir Yükleyici Program tarafından sahiplenilir.

Program HesabıProgram Hesabı

Basitlik açısından, program hesabını programın kendisi olarak düşünebilirsiniz. Bir programın talimatlarını çağırdığınızda, program hesabının adresini (yaygın olarak "Program ID" olarak adlandırılır) belirtirsiniz.

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.

Bir Solana programı dağıttığınızda, program bir program hesabında saklanır. Program hesapları bir Yükleyici Program tarafından sahiplenilir. Yükleyicinin birkaç versiyonu vardır, ancak loader-v3 hariç hepsi çalıştırılabilir kodu doğrudan program hesabında saklar. Loader-v3, çalıştırılabilir kodu ayrı bir "program veri hesabında" saklar ve program hesabı sadece ona işaret eder. Yeni bir program dağıttığınızda, Solana CLI varsayılan olarak en son yükleyici sürümünü kullanır.

Tampon Hesabı

Loader-v3, dağıtım veya yeniden dağıtım/yükseltmeler sırasında bir programın yüklenmesini geçici olarak hazırlamak için özel bir hesap türüne sahiptir. Loader-v4'te hala tamponlar vardır, ancak bunlar sadece normal program hesaplarıdır.

Program Veri Hesabı

Loader-v3, diğer tüm BPF Yükleyici programlarından farklı çalışır. Program hesabı sadece gerçek çalıştırılabilir kodu saklayan bir program veri hesabının adresini içerir:

Program Veri HesabıProgram Veri Hesabı

Bu program veri hesaplarını, programların veri hesaplarıyla (aşağıya bakın) karıştırmayın.

Veri Hesabı

Solana'da, bir programın yürütülebilir kodu, programın durumundan farklı bir hesapta saklanır. Bu, işletim sistemlerinin genellikle programlar ve verileri için ayrı dosyalara sahip olma şekline benzer.

Durumu korumak için, programlar sahip oldukları ayrı hesaplar oluşturmak için talimatlar tanımlar. Bu hesapların her biri kendi benzersiz adresine sahiptir ve program tarafından tanımlanan herhangi bir keyfi veriyi saklayabilir.

Veri HesabıVeri Hesabı

Yalnızca System Program'ın yeni hesaplar oluşturabileceğini unutmayın. System Program bir hesap oluşturduktan sonra, yeni hesabın sahipliğini başka bir programa aktarabilir veya atayabilir.

Başka bir deyişle, özel bir program için veri hesabı oluşturmak iki adım gerektirir:

  1. Bir hesap oluşturmak için System Program'ı çağırın, ardından sahipliği özel programa aktarın
  2. Artık hesabın sahibi olan özel programı çağırın ve programın talimatında tanımlandığı şekilde hesap verilerini başlatın

Bu hesap oluşturma süreci genellikle tek bir adım olarak soyutlanır, ancak altta yatan süreci anlamak faydalıdır.

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
} from "@solana-program/token-2022";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://127.0.0.1:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer
const feePayer = await generateKeyPairSigner();
// Fund fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Instruction to create new account for mint (token 2022 program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token 2022 program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: feePayer.address
});
const instructions = [createAccountInstruction, initializeMintInstruction];
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Create transaction message
const 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 transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const 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);
Console
Click to execute the code.

Is this page helpful?

İçindekiler

Sayfayı Düzenle