In 2024, Solana emerged as a dark horse, with its TVL soaring from $1 billion at the beginning of the year to nearly $5 billion today, becoming the fourth largest public chain.
Compared with Ethereum, Solana provides users with a more superior experience at a faster speed and lower fees. Its POH-based consensus mechanism and asynchronous transaction execution mode provide developers with high throughput and low-latency blockchain performance, making it the preferred platform for various decentralized applications.
BlockSec has specially planned a series of articles on "Playing with Solana", covering the basic concepts of Solana, a practical guide to viewing and analyzing Solana transactions, and a tutorial on writing Solana smart contracts.
As the first issue of this series, this article will introduce the key concepts in the Solana network in depth, including its operating mechanism, account model and transactions, laying the foundation for everyone to write correct and efficient Solana contracts.
eBPF: The cornerstone of Solana transaction execution
In order to write and execute smart contracts, blockchains often require a set of programming languages and Turing-complete computing environments.
Friends familiar with Ethereum should know that smart contracts on Ethereum are usually written in the high-level language Solidity, and the bytecode generated by Solidity compilation runs in an environment called the Ethereum Virtual Machine.
Solana did not choose to develop a completely new virtual environment and language, but made full use of existing excellent technologies. The eBPF (extended Berkeley Packet Filter) virtual machine, which was originally used to expand the functions of the Linux kernel, was selected by Solana as the underlying execution environment.
So, what are the advantages of eBPF over EVM?
Compared to EVM, which only supports interpreted execution, eBPF can directly convert bytecode into machine instructions that can be directly executed by the processor in just-in-time (JIT) mode, thereby running programs more efficiently.
eBPF has an efficient instruction set and mature infrastructure. Developers only need to use the Rust language to write smart contracts. The LLVM compilation framework provides an eBPF backend, which can be used to directly compile these Rust programs into bytecodes that can run on the eBPF virtual machine.
Solana's Account Model
1. Solana Account Structure
Data on Solana is stored in the form of accounts. As shown in the figure below, we can regard all data in Solana as a huge key-value database. The key of the database is the address of the account. For a "wallet" account (that is, an account directly controlled by a Solana user through a public-private key pair), this address is a public key generated using the Ed25519 signature system; and the value of the database is the specific information of the account, including the balance and other related information.
Solana uses a structure called AccountInfo to describe an account, and its composition is shown in the figure below.
Each account in Solana contains four fields. Here we explain them one by one.
Data field stores data related to the account. If the account is a program (i.e., a smart contract), it actually stores eBPF bytecode. Otherwise, the information format in Data is generally defined by the account creator.
Executable field is used to identify whether the account is a program. It should be noted that, unlike Ethereum, programs in Solana can be updated.
Lamports field records the balance of Solana tokens in the account. Lamports is actually the smallest unit of SOL Token (1 SOL = 1 billion Lamports).
Owner field indicates the owner of the current account. In Solana, any account has an "Owner". For example, the owner of all "wallet" accounts is System Program, which is a special account on the Solana network responsible for account creation and other functions. The account owner is the only one who can modify account data and deduct Lamports balance (but anyone can add Lamports, that is, perform transfer functions to the account).
2. Predefined Solana Accounts
Solana has a set of predefined running programs called Native Programs, which are deployed on fixed addresses. As the Solana network is upgraded, these predefined programs may also be updated. We can think of these programs as APIs and library functions that provide specific functions under the Solana network.
In Native Programs, a program that developers often need to interact with is the System Program. The System Program provides developers with some instructions (Instructions), and we can think of each instruction as an independent method. For example, developers can use the CreateAccount instruction to create a new account, or use the Transfer instruction to transfer Lamports to other accounts.
Another common Native Programs is the BPF Loader program. It is the owner of all other program accounts and is responsible for deploying, updating, and executing specific programs. When a "wallet" account needs to update the program it has deployed, it is actually done by delegating the BPF Loader program. After all, only the owner of the program has direct authority to modify the data.
In addition to Native Programs, Solana also provides a group of accounts called Sysvar. They provide programs on Solana with information and global variables related to the current state of the Solana network, such as the current clock, the most recent block hash, etc.
3. Account Rent
On the Solana chain, each account needs to maintain a certain number of Lamports as a minimum amount, which is called rent. Unlike the concept of rent in real life, rent on Solana is recoverable. In order to ensure that the account's on-chain data is available, the account needs to hold a corresponding number of Lamports. The amount of rent is related to the size of the account's on-chain storage space.
Any transaction that attempts to reduce the account balance to less than the rent amount will fail, unless the transaction directly reduces the account balance to zero. This operation indicates that the account's rent has been recovered, and at the end of the transaction execution, Solana will clear the storage space of the corresponding account through garbage collection.
- ? View "Solana Account" in the Browser
In order to help everyone better understand the relevant concepts, we used the "Hello World" project provided by Solana to create a program account. You can use Solana's blockchain browser Solscan to view the relevant information of the following accounts?.
CJWhxB4qEWBv9eGYUkTN881bNDMDkLbzH1FmdwqLLhoe
As shown in the figure above, we can first see that the account has been marked as "Program" by the Solana browser. When the account was created, a portion of Lamports was deducted from the sender's balance as the rent of the account, so we can see that its SOL Balance field is not empty.
Secondly, since we created a program, its Executable field is Yes. There may be a difficult place to understand here, that is, readers may find that the Data field stores an address rather than an eBPF program. We mentioned earlier that Solana allows programs to be updated, and it is actually implemented through a "proxy" mode. Since Solana does not allow direct modification of program accounts, it creates a data account to store eBPF programs, and the Data field of the program account only stores the address of the data account. Whenever you need to update the program, you only need to modify the Data field in the data account. We use Solscan to view the account in the Executable Data field and find that it is marked as "Program Executable Data Account", and its Data field stores the actual program:
Going back to the previous picture, we can find that the Owner field in More info is BPF Loader, which is consistent with our description in the previous section.
There is also a field called "Upgrade Authority" in Overview. What does it mean?
As we mentioned earlier, the "wallet" account is updated by delegating the BPF Loader. Before the update, the BPF Loader needs to verify whether the delegator has the permission to update. Since the Owner field of the program account is already the BPF Loader, it has no space to store this information. Therefore, Solana chooses to store this information in the Data field of the data account. This information is actually the wallet address of the deployed program, which is the "Upgrade Authority" here. The figure below shows the relationship between the program account and the data account. You can see that the Data field of the data account consists of two parts of information: the wallet address and the eBPF code.
Solana's Transactions and Instructions
In Solana, users also execute programs by issuing transactions. What’s special about it is that Solana can execute these transactions in parallel, which is an important reason why it can provide lightning-fast transaction speeds. Next, let’s take a look at how Solana’s transactions are designed.
A Solana transaction consists of a signature and a message body. A transaction can contain multiple signatures. The message body of a transaction consists of four parts, as shown in the figure below.
The two fields of the message, the header and the compact array of account addresses, specify all the accounts involved in the transaction and the characteristics of the accounts in the transaction: including whether the account provides a signature and whether it will be written during the execution process. Using this information, Solana can verify the signatures provided by the corresponding accounts and can execute transactions that do not touch the same set of accounts in parallel.
The most recent block hash is the timestamp of the transaction. The Solana network ensures that the transaction comes from the most recent 150 blocks, otherwise the transaction will be considered expired and will not be executed.
The instruction array (Compact array of Instructions) is the most important part of the transaction, containing one or more instructions. An instruction is actually a call to a routine provided by a program. The instruction consists of three fields, as shown in the figure below:
The first field, Program ID Index, specifies the recipient of the instruction, that is, the on-chain program that needs to process the instruction. It does not directly store a 32-byte address, but places the address in the account address array in the message body. This field uses a one-byte subscript to indicate its position in the array, achieving a kind of space reuse.
Similar to the first field, the second field is an array of account address subscripts (Compact array of account address indexes), which indicates all accounts involved in processing the instruction.
The last field is a byte array, which is additional information required by the program to process the instruction. It can be understood as a function parameter.
It should be noted that Solana will process all instructions in the transaction in sequence and ensure that the execution of the transaction is atomic. This means that the instructions in a transaction will either all fail or all execute successfully. There will be no situation where some instructions are executed successfully and some fail.
- ? View "Solana Transactions" in the Browser
We use another Solana browser to view the transactions of the program account created earlier?. In Overview, you can see the signature of the Solana transaction, the hash of the latest block, and other information:
3uKQ85Lpsnwb5D6CgUntoMyJX3tSaeGb4pjUoMaMyNVqQNPp5PRG1kJEEEk3YNdWLYEMZGmoJ5Rowgon8hZzwL9D
In Account Input, all accounts involved in the current transaction and the characteristics of the related accounts in the transaction are listed. We can see that in addition to the sender, program account and other addresses, two Native Programs and Sysvar accounts are also included.
Since this transaction is a simple program creation transaction, it only contains two instructions. The recipient of the first instruction is the System Program, which is responsible for creating the program account; the recipient of the second instruction is the BPF Loader, which is responsible for writing the actual deployed eBPF code into the data account and writing its address into the Data field of the program account.
Summary
The smart contract on Solana is developed in Rust and runs on the eBPF virtual machine. It follows the account model, and the accounts on the chain need to maintain rent to ensure the availability of data. A transaction consists of one or more instructions, which clearly defines all dependent accounts, so that transactions can be processed in parallel, improving throughput and reducing response latency. These features have jointly promoted the rapid development of Solana, making it one of the most popular blockchain platforms.