Modelo de Conta Solana
Na Solana, todos os dados são armazenados no que chamamos de "contas". Você pode pensar nos dados na Solana como um banco de dados público com uma única tabela "Contas", onde cada entrada nesta tabela é uma "conta". Cada conta da Solana compartilha o mesmo tipo de Conta base.
Contas
Pontos-chave
- As contas podem armazenar até 10MiB de dados, que contêm código de programa executável ou estado do programa.
- As contas exigem um depósito de rent em lamports (SOL) que é proporcional à quantidade de dados armazenados, e você pode recuperá-lo totalmente ao fechar a conta.
- Cada conta tem um proprietário de programa. Apenas o programa que possui uma conta pode alterar seus dados ou deduzir seu saldo de lamport. Mas qualquer pessoa pode aumentar o saldo.
- Contas Sysvar são contas especiais que armazenam o estado do cluster da rede.
- Contas de programa armazenam o código executável de contratos inteligentes.
- Contas de dados são criadas por programas para armazenar e gerenciar o estado do programa.
Conta
Cada conta na Solana tem um endereço único de 32 bytes, frequentemente mostrado
como uma string codificada em base58 (por exemplo,
vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo6Xd7D
).
A relação entre a conta e seu endereço funciona como um par chave-valor, onde o endereço é a chave para localizar os dados on-chain correspondentes da conta. O endereço da conta atua como o "ID único" para cada entrada na tabela "Contas".
Endereço da Conta
A maioria das contas Solana usa uma chave pública Ed25519 como seu endereço.
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
Embora as chaves públicas sejam comumente usadas como endereços de conta, a Solana também suporta um recurso chamado Program Derived Addresses (PDAs). PDAs são endereços especiais que você pode derivar deterministicamente de um ID de programa e entradas opcionais (seeds).
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}`);
Tipo de Conta
As contas têm um tamanho máximo de 10MiB e todas as contas na Solana compartilham o mesmo tipo base Account.
Tipo de Conta
Cada conta na Solana tem os seguintes campos:
data
: Um array de bytes que armazena dados arbitrários para uma conta. Para contas não executáveis, isso geralmente armazena o estado que deve ser lido. Para contas de programa (smart contracts), isso contém o código do programa executável. O campo de dados é comumente chamado de "dados da conta".executable
: Esta flag mostra se uma conta é um programa.lamports
: O saldo da conta em lamports, a menor unidade de SOL (1 SOL = 1 bilhão de lamports).owner
: O ID do programa (chave pública) do programa que possui esta conta. Apenas o programa proprietário pode alterar os dados da conta ou deduzir seu saldo de lamports.rent_epoch
: Um campo legado de quando a Solana tinha um mecanismo que deduzia periodicamente lamports das contas. Embora este campo ainda exista no tipo Account, ele não é mais usado desde que a coleta de rent foi descontinuada.
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
Para armazenar dados na blockchain, as contas também devem manter um saldo em lamport (SOL) que é proporcional à quantidade de dados armazenados na conta (em bytes). Este saldo é chamado de "rent", mas funciona mais como um depósito porque você pode recuperar o valor total ao fechar uma conta. Você pode encontrar o cálculo aqui usando estas constantes.
O termo "rent" vem de um mecanismo obsoleto que deduzia regularmente lamports de contas que ficavam abaixo do limite de rent. Este mecanismo não está mais ativo.
Proprietário do programa
Na Solana, os "smart contracts" são chamados de programas. A propriedade do programa é uma parte fundamental do Modelo de Conta da Solana. Cada conta tem um programa designado como seu proprietário. Apenas o programa proprietário pode:
- Alterar o campo
data
da conta - Deduzir lamports do saldo da conta
Programa do sistema
Por padrão, todas as novas contas pertencem ao Programa do Sistema. O Programa do Sistema faz algumas coisas importantes:
- Criação de novas contas: Apenas o Programa do Sistema pode criar novas contas.
- Alocação de espaço: Define a capacidade em bytes para o campo de dados de cada conta.
- Transferência / Atribuição de propriedade do programa: Uma vez que o Programa do Sistema cria uma conta, ele pode reatribuir o proprietário do programa designado para uma conta de programa diferente. É assim que programas personalizados assumem a propriedade de novas contas criadas pelo Programa do Sistema.
Todas as contas de "carteira" na Solana são apenas contas pertencentes ao Programa do Sistema. O saldo em lamport nessas contas mostra a quantidade de SOL pertencente à carteira. Apenas contas pertencentes ao Programa do Sistema podem pagar taxas de transação.
Conta do Sistema
Contas Sysvar
Contas Sysvar são contas especiais em endereços predefinidos que fornecem acesso aos dados de estado do cluster. Essas contas são atualizadas dinamicamente com dados sobre o cluster da rede. Você pode encontrar a lista completa de Contas Sysvar aqui.
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);
Conta de Programa
Implantar um programa Solana cria uma conta de programa executável. A conta de programa armazena o código executável do programa.
Contas de programa são de propriedade de um Programa Carregador.
Conta de Programa
Para simplificar, você pode tratar a conta do programa como o próprio programa. Quando você invoca as instruções de um programa, você especifica o endereço da conta do programa (comumente chamado de "ID do Programa").
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);
Quando você implanta um programa Solana, ele é armazenado em uma conta de programa. Contas de programa são de propriedade de um Programa Carregador. Existem várias versões do carregador, mas todas, exceto o loader-v3, armazenam o código executável diretamente na conta do programa. O loader-v3 armazena o código executável em uma "conta de dados do programa" separada, e a conta do programa apenas aponta para ela. Quando você implanta um novo programa, a CLI Solana usa a versão mais recente do carregador por padrão.
Conta Buffer
O loader-v3 possui um tipo especial de conta para temporariamente preparar o upload de um programa durante a implantação ou reimplantação/atualizações. No loader-v4, ainda existem buffers, mas são apenas contas de programa normais.
Conta de Dados do Programa
O Loader-v3 funciona de maneira diferente de todos os outros programas BPF Loader. A conta do programa contém apenas o endereço de uma conta de dados do programa, que armazena o código executável real:
Conta de Dados do Programa
Não confunda essas contas de dados do programa com as contas de dados dos programas (veja abaixo).
Conta de Dados
Na Solana, o código executável de um programa é armazenado em uma conta diferente da conta de estado do programa. Isso é semelhante a como os sistemas operacionais normalmente têm arquivos separados para programas e seus dados.
Para manter o estado, os programas definem instruções para criar contas separadas que eles possuem. Cada uma dessas contas tem seu próprio endereço único e pode armazenar qualquer dado arbitrário definido pelo programa.
Conta de Dados
Observe que apenas o System Program pode criar novas contas. Uma vez que o System Program cria uma conta, ele pode então transferir ou atribuir a propriedade da nova conta para outro programa.
Em outras palavras, criar uma conta de dados para um programa personalizado requer duas etapas:
- Invocar o System Program para criar uma conta e depois transferir a propriedade para o programa personalizado
- Invocar o programa personalizado, que agora possui a conta, para inicializar os dados da conta conforme definido pela instrução do programa
Este processo de criação de conta é frequentemente abstraído como uma única etapa, mas é útil entender o processo subjacente.
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?