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.
Hesaplar
Ö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 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 keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
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}`);
Hesap Türü
Hesaplar maksimum 10MiB boyutunda olabilir ve Solana'daki her hesap aynı temel Account türünü paylaşı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.
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,}
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);
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ı
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);
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ı
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);
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ı
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ı
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:
- Bir hesap oluşturmak için System Program'ı çağırın, ardından sahipliği özel programa aktarın
- 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 exampleconst rpc = createSolanaRpc("http://127.0.0.1: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);
Is this page helpful?