Solana Hesap Modeli
Solana'da tüm veriler "hesaplar" olarak adlandırılan yapılarda saklanır. Solana'daki verileri, her girişin bir "hesap" olduğu tek bir "Hesaplar" tablosuna sahip genel bir veritabanı olarak düşünebilirsiniz. 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 hesapları, 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
vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo6Xd7M7ag
).
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) belirleyici bir şekilde 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 Hesap aşağıdaki alanlara sahiptir:
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 beri 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 bakiye "rent" olarak adlandırılır, ancak bir hesabı kapattığınızda tam tutarı geri alabileceğiniz için daha çok depozito gibi çalışır. 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" program 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
Sistem Programı
Varsayılan olarak, tüm yeni hesaplar Sistem Programı tarafından sahiplenilir. Sistem Programı birkaç önemli işlev yapar:
- Yeni Hesap Oluşturma: Yalnızca Sistem Programı yeni hesaplar oluşturabilir.
- Alan Tahsisi: Her hesabın veri alanı için bayt kapasitesini belirler.
- Program Sahipliğini Transfer Etme / Atama: Sistem Programı bir hesap oluşturduktan sonra, belirlenmiş program sahibini farklı bir program hesabına yeniden atayabilir. Özel programların Sistem Programı tarafından oluşturulan yeni hesapların sahipliğini alması bu şekilde gerçekleşir.
Solana'daki tüm "cüzdan" hesapları, sadece Sistem Programı tarafından sahiplenilen hesaplardır. Bu hesaplardaki lamport bakiyesi, cüzdanın sahip olduğu SOL miktarını gösterir. Yalnızca Sistem Programı tarafından sahiplenilen hesaplar işlem ücretlerini ödeyebilir.
Sistem Hesabı
Sysvar Hesapları
Sysvar hesapları, küme durumu 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 Hesabı
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 dışındaki tüm versiyonlar ç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 buna işaret eder. Yeni bir program dağıttığınızda, Solana CLI varsayılan olarak en son yükleyici versiyonunu 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 Sistem Programı'nın yeni hesaplar oluşturabileceğini unutmayın. Sistem 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 Sistem Programı'nı ç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?