banner
[面包]MrTwoC

[面包]MrTwoC

你好,欢迎来到这个基于区块链的个人博客 名字:面包 / MrTwoc 爱好:跑步(5/10KM)、咖啡、游戏(MMORPG、FPS、Minecraft、Warframe) 兴趣方向:Rust、区块链、网络安全、量子信息(量子计算)、游戏设计与开发
bilibili
steam
email
github

0x05 Solana.1

About Blockchain Consensus Mechanisms
pow, pos, poa, poh
Comprehensive Introduction to Solana - Consensus, Wallet, Ecosystem, Contracts | Denglian Community | Blockchain Technology Community
Guide: Building Solana Programs with Anchor | Denglian Community | Blockchain Technology Community
3-Minute Token Creation Tutorial on Solana: No-Code Token Issuance Platform PandaTool Supported | Denglian Community | Blockchain Technology Community

New Consensus Mechanism - Proof of History (PoH)
The World's Fastest "High-Speed Public Chain" - Solana
The basic consensus of Solana is PoS (i.e., the common Proof of Stake mechanism), which simply means that the interest distribution is determined based on the amount of currency held by the user and the time (coin age) it has been held.
Proof of History (PoH) is a clever and highly practical innovation of Solana. Traditional blockchains, such as Bitcoin and Ethereum, couple time and state together, where a globally consistent state can only be produced when a new block is born. Solana cleverly separates the hash-based time chain and state, not linking the hashes of each block together, but having the validators in the network hash the hashes within the blocks themselves; this mechanism is called PoH (Proof of History).
Solana Development Learning Notes (1) - Starting from Hello World | Denglian Community | Blockchain Technology Community
Solana Programming Model: Introduction to Solana Development | Denglian Community | Blockchain Technology Community

Cluster#

It is the core of Solana's architecture, where a group of validators jointly processes transactions and maintains a single ledger. Solana has several different clusters, each with specific purposes:
Localhost: The local development cluster with the default port 8899. The Solana Command Line Interface (CLI) has a built-in test validator that can be customized according to the developer's personal needs, without airdrops and with no rate limits.
Development Network Devent: A worthless environment for testing and experimentation.
Test Network Testnet: A place for core personnel to experiment with new updates and features, and also for performance testing.
Mainnet Beta: A live, permissionless place that generates real currency transactions.

Solana Accounts#

  1. Accounts that store data
  2. Accounts that store executable programs
  3. Accounts that store native programs

They can be distinguished by function:

  1. Executable accounts
  2. Non-executable accounts (do not contain code)

Each non-executable account has different types:

  • Associated Token Account - An account that contains specific token information, its balance, and owner information (e.g., Alice owns 10 USDC)
  • System Account - An account created and owned by the System Program
  • Staking Account - An account used to delegate tokens to validators for potential rewards

Account Structure#

pub struct AccountInfo<'a> {
    pub key: &'a Pubkey,
    pub lamports: Rc>,
    pub data: Rc>,
    pub owner: &'a Pubkey,
    pub rent_epoch: Epoch,
    pub is_signer: bool,
    pub is_writable: bool,
    pub executable: bool,
}

Accounts are identified by their address (key), which is a unique 32-byte public key.
The lamports field holds the number of lamports owned by this account. One lamport equals one billionth of Solana's native token SOL.
The data refers to the raw byte array of data stored by this account. It can store anything from metadata of digital assets to token balances and can be modified by programs.
The owner field contains the owner of this account, represented by the address of the program account. There are some rules regarding account ownership:

  • Only the owner of the account can change its data and withdraw lamports
  • Anyone can deposit lamports into the account
  • The owner of the account can transfer ownership to a new owner, provided that the account's data is reset to zero

The rent_epoch field indicates that this account will owe rent in the next epoch period. An epoch is the number of slots scheduled by the leader. Unlike traditional files in an operating system, accounts on Solana have a lifespan represented in lamports. The continued existence of an account depends on its lamport balance, which introduces the concept of rent.
The is_signer field is a boolean indicating whether the transaction has been signed by the owner of the involved account. In other words, it tells the program accounts involved in the transaction whether the account is a signer. Being a signer means the account holds the private key corresponding to the public key and has the authority to approve the proposed transaction.
The is_writable field is a boolean indicating whether the account's data can be modified. Solana allows transactions to specify an account as read-only to facilitate parallel processing. While the runtime allows different programs to access read-only accounts simultaneously, it handles potential write conflicts on writable accounts using transaction processing order. This ensures that only non-conflicting transactions can be processed in parallel.
The executable field is a boolean indicating whether the account can process instructions. Yes, this means programs are stored in the account, and we will delve into this in the next section. First, we need to introduce the concept of rent.

Rent#

The storage cost incurred to keep an account active and ensure it is retained in the validator's memory. Rent is charged based on epoch assessments, which are defined time units.

  • Rent Charge - Rent is charged once per epoch. Rent can also be charged when an account is referenced in a transaction.
  • Rent Distribution - A portion of the collected rent is burned, meaning it is permanently removed from circulation. The remainder is distributed to voting accounts after each slot.
  • Rent Payment - If an account does not have enough lamports to pay rent, its data will be removed, and the account will be deallocated in a process called garbage collection.
  • Rent Exemption - If an account maintains a minimum balance equal to two years' worth of rent payments, it can become rent-exempt. All new accounts must meet this rent exemption threshold, which depends on the size of the account.
  • Rent Retrieval - Users can close an account to retrieve its remaining lamports. This allows users to reclaim the rent stored in the account.

The getMinimumBalanceForRentExemption RPC endpoint can be used to estimate the rent for a specific account size. Test Drive simplifies this process by accepting the length of account data in usize. The Solana rent CLI subcommand can also be used to estimate the minimum SOL amount required for an account to become rent-exempt. For example, at the time of writing, running the command solana rent 20000 will return the minimum rent exemption value: 0.14009088 SOL.

Solana Addresses#

There are two "types" of addresses on Solana.
Solana uses ed25519, an EdDSA signature scheme that uses SHA-512 (SHA-2) and the Curve25519 elliptic curve to create addresses. It generates 32-byte public keys, which can be used directly as the primary address format since they are not hashed.
For an address to be valid, it must be a point on the ed25519 curve. However, not all addresses need to be derived from this curve. Program-derived addresses (PDAs) are generated outside the curve, meaning they do not have corresponding private keys and cannot be used for signing. PDAs are created by the System Program and are used when a program needs to manage accounts.

Differences Between Solana Accounts and Ethereum Accounts#

Ethereum contains two types of accounts (EOA, contract accounts), where contract accounts have contract code management and cannot initiate transactions.
Any account on Solana can potentially become a program. Code and data are separated.
Solana has no state and interacts with various data accounts without redundant deployments. Interactions between different programs do not require asset transfers.
Solana requires rent payments, necessitating a minimum balance to remain active. Inactivity or insufficient funds will lead to reclamation.

What is a Program#

A program is an executable account owned by the BPF Loader. It is executed by the Solana Runtime, which is designed to handle transactions and program logic.
The Solana programming model features: separation of code and data. Programs have no state and do not store state. All data exists in accounts and is passed to programs in a referenced manner through transactions.
Capabilities of Solana programs:

  1. Own additional accounts
  2. Access/read funds from other accounts
  3. Modify data/deduct from owned accounts

Two Types of Programs

  • On-chain Programs - User-written programs deployed on Solana. They can be upgraded through their upgrade authority, which is usually the account that deployed the program.
  • Native Programs - These programs are integrated into the Solana core. They provide the essential functions required for validators to operate. Native programs can only be upgraded through network-wide software updates. Common examples include the System Program, BPF Loader Program, and Vote Program.

Programs are typically developed using Rust language, aided by the development framework: Anchor, to simplify program creation.

What is a Transaction#

It is the pillar of on-chain activity. It is the mechanism for calling programs and implementing state changes. A transaction on Solana is a bundle of a series of instructions.
Components of a transaction:

  • An array of accounts to read from or write to
  • One or more instructions
  • One or more signatures

The structure of a Solana transaction provides the information required for network processing and verification operations.

pub struct Transaction {
    pub signatures: Vec,
    pub message: Message,
}

The signatures field contains a set of signatures corresponding to the serialized Message. Each signature is associated with an account key from the account_keys list in the Message, starting with the fee payer. The fee payer is the account responsible for paying the transaction fee during processing. This is usually the account initiating the transaction. The number of required signatures equals the num_required_signatures defined in the MessageHeader of the message.
The message itself is a structure of type Message, defined as follows:

pub struct Message {
    pub header: MessageHeader,
    pub account_keys: Vec,
    pub recent_blockhash: Hash,
    pub instructions: Vec,
}

The header contains three unsigned 8-bit integers: the number of required signatures (i.e., num_required_signatures), the number of read-only signers, and the number of read-only non-signers.
The account_keys field lists all account addresses involved in the transaction. Accounts requesting read/write access appear first, followed by read-only accounts.
The recent_blockhash is a recent block hash that contains a 32-byte SHA-256 hash. This indicates the last time the client observed the ledger and serves as the lifecycle for recent transactions. Validators will reject transactions with old block hashes. Additionally, the inclusion of the recent block hash helps prevent duplicate transactions, as any transaction that is exactly the same as a previous one will be rejected. If for any reason a transaction needs to be signed long before submission to the network, a persistent transaction nonce can be used in place of the recent block hash to ensure it is a unique transaction.
The instructions field contains one or more CompiledInstruction structures, each indicating a specific operation for the network validators to execute.

Instructions#

Instructions are directives for a single Solana program call. They are the smallest unit of execution logic within a program and the most basic operational unit on Solana. Programs interpret the data passed from the instructions and operate on the specified accounts. The Instruction structure is defined as follows:

pub struct Instruction {
    pub program_id: Pubkey,
    pub accounts: Vec,
    pub data: Vec,
}

The program_id field specifies the public key of the program to be executed. This is the address of the program that will process the instruction. The owner of the program account indicated by this public key specifies the loader responsible for initializing and executing the program. Once deployed, the loader marks the on-chain Solana bytecode format (SBF) program as executable. The Solana runtime will reject any transaction attempting to call an account that is not marked as executable.
The accounts field lists the accounts that the instruction may read from or write to. These accounts must be provided as AccountMeta values. Any account whose data may be changed by the instruction must be specified as writable; otherwise, the transaction will fail. This is because programs cannot write to accounts they do not own or have the necessary permissions for. This also applies to changing the lamports of accounts: subtracting lamports from an account not owned by the program will cause the transaction to fail, while adding lamports to any account is allowed. The accounts field can also specify accounts that the program will not read from or write to. This is to influence the scheduling of program execution through the runtime, but these accounts will be ignored.
The data is a generic vector containing 8-bit unsigned integers used as input passed to the program. This field is crucial as it contains the encoded instructions that the program will execute.
Solana is agnostic to the format of instruction data. However, it has built-in support for bincode and borsh (a binary object representation serializer for hashing). Serialization is the process of converting complex data structures into a series of bytes that can be transmitted or stored. The choice of encoding for the data should consider the overhead of decoding, as all of this occurs on-chain. Borsh serialization is generally preferred over bincode due to its stable specification, JavaScript implementation, and generally greater efficiency.
Programs use helper functions to simplify the construction of instructions. For example, the system program provides a helper function to construct the SystemInstruction::Assign instruction:

pub fn assign(pubkey: &Pubkey, owner: &Pubkey) -> Instruction {
    let account_metas = vec![AccountMeta::new(*pubkey, true)];
    Instruction::new(
        system_program::id(),
        &SystemInstruction::Assign { owner: *owner },
        account_metas,
    )
}

This function constructs an instruction that, when processed, will change the owner of the specified account to the new owner provided.
A single transaction can contain multiple instructions, which are executed sequentially and atomically. This means either all instructions succeed, or none do. This also means the order of instructions can be crucial. Programs must be hardened to safely handle any potential sequence of instructions to prevent any potential exploits.
For example, during deinitialization, a program may attempt to deinitialize an account by setting its lamport balance to zero. This assumes that the Solana runtime will delete the account. This assumption is valid between transactions but not between instructions or across program calls (which we will cover in later articles on cross-program calls). Programs should explicitly zero out the account's data to harden against potential flaws during the deinitialization process. Otherwise, an attacker could issue subsequent instructions to exploit the assumed deletion, such as reusing the account before the transaction completes.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.