#1 - A Starter Kit for New Solana Developer
Author: @ironaddicteddog
[Updated at 2022.3.31]
TL; DR
What makes Solana so fast and efficient?
What should I learn at minimum to understand how Solana program works?
How can I setup my the environment quickly?
What is the best practice to develop Solana programs?
Before We Start
Prerequisites
Solidity (nice to have)
Why Solana?
It's a new blockchain paradigm evolved from Ethereum (more or less)
It's blazing fast and efficient, meaning it will be cheap and affordable for average users
It's a good investment on modern web technology (Rust / Typescript, etc)
Why Rust?
Rust is fast
Rust is safer (compared to C++)
Rust can be compiled to WASM
(Almost) every programmable blockchain has a rust implementation
...and of course, Solana
Compare Solana to Ethereum, what are the pros and cons?
Pros
Parallelism is the secret sauce making it blazing fast
Efficient network synchronization using PoH Clock
Verification can be parallelized
Efficient PoS Consensus
Tower BFT, a specialized PBFT designed for PoH
Cons
Rather high hardware requirements to run a validator
12 cores CPU
N cores GPU
128GB RAM
Structure of this Kit
Hello world (for environment setup)
Escrow program using vanilla Rust (for learning core concepts)
Escrow program using Anchor (for learning the best practice)
1. Hello World!
Goal
Setup the development environment
Get familiar with tools such as:
cargo
cargo build-bpf
rustup
solana-cli
solana deploy
solana-test-validator
solana-web3.js
Install Rust and Solana Cli
See this doc for more details
Install rustup
rustup
Install solana-cli
solana-cli
See this doc for more details
Note: You may have to build from source if you are using Mac M1 machine. See this doc for more installation details.
Generate Keypair
Or, you can recover your key from your existing key phrase:
Config the keypath:
Config to Local Cluster
Install rust-analyzer
, Better TOML
and crates
(Optional)
rust-analyzer
, Better TOML
and crates
(Optional)See this repo for more details
rust-analyzer
can be very handy if you are using Visual Studio Code. For example, the analyzer can help download the missing dependencies for you automatically.
Install Additional Dependencies (Optional)
If you are using Linux, you may need to install these tools as well:
Build and Deploy
See this repo for full code base
First, let's clone the repo:
Run solana-test-validator
in another terminal session:
Next, let's compile the hello world program:
Deploy the program after compilation, :
If you encounter an insuffficient fund error, you may have to request for an aidrop:
Say Hello World
First, we need to modify the PROGRAM_PATH
in src/client/hello_world.ts
:
Finally, let's make the program say Hello by sending a transaction:
If we take a closer look to function sayHello
, we can see how a solana transaction is constructed and sent:
2. Escrow Program (using vanilla Rust)
Goal
Learn Solana account model and core concepts such as:
Account model
Program Architecture
Program Derived Address (PDA)
Cross-Program Invocation (CPI)
invoke
invoke_signed
This section is extracted from this awesome tutorial: Programming on Solana - An Introduction (by paulx). Some of the explanations in this doc are more comprehensive and clearer in the original post. I strongly recommend you to read through the post at least once.
Program Architecture
lib.rs
: registering modulesentrypoint.rs
: entrypoint to the programinstruction.rs
: program API, (de)serializing instruction dataprocessor.rs
: program logicstate.rs
: program objects, (de)serializing stateerror.rs
: program specific errors
See this repo for full code base
Core Concepts
Account
Accounts are used to store state
Accounts are owned by programs
Only the account owner may debit an account and adjust its data
All accounts to be written to or read must be passed into the entrypoint
All internal Solana internal account information are saved into fields on the account (opens new window)but never into the data field which is solely meant for user space information
Developers should use the data field to save data inside accounts
Program
Solana programs are stateless
Each program is processed by its BPF Loader and has an entrypoint whose structure depends on which BPF Loader is used
In theory, programs have full autonomy over the accounts they own. It is up to the program's creator to limit this autonomy and up to the users of the program to verify the program's creator has really done so
The flow of a program using this structure looks like this:
Someone calls the entrypoint
The entrypoint forwards the arguments to the processor
The processor asks instruction module to decode the instruction_data argument from the entrypoint function.
Using the decoded data, the processor will now decide which processing function to use to process the request.
The processor may use state module to encode state into or decode the state of an account which has been passed into the entrypoint.
When writing Solana programs, be mindful of the fact that any accounts may be passed into the entrypoint, including different ones than those defined in the API inside
instruction.rs
. It's the program's responsibility to check that received accounts == expected accounts
Instruction
If you are familiar of Ethereum, think of Solana instructions as Ethereum transcations, while Solana transaction, which can wrap multiple instructions, is anologous to Ethereum
multicall
SPL token
Program
token
ProgramThe token program owns token accounts which inside their data field hold relevant information
the token program also owns token mint accounts with relevant data
each token account holds a reference to their token mint account, thereby stating which token mint they belong to
the token program allows the (user space) owner of a token account to transfer its ownership to another address
All internal Solana internal account information are saved into fields on the account but never into the data field which is solely meant for user space information
PDA
Program Derived Addresses do not lie on the ed25519 curve and therefore have no private key associated with them.
Cross-Program Invocation
When including a signed account in a program call, in all CPIs including that account made by that program inside the current instruction, the account will also be signed, i.e. the signature is extended to the CPIs.
when a program calls
invoke_signed
, the runtime uses the given seeds and the program id of the calling program to recreate the PDA and if it matches one of the given accounts inside invoke_signed's arguments, that account's signed property will be set to true
To spend Solana SPL, you don't need to approve. Why?
Rent
Rent is deducted from an account's balance according to their space requirements (i.e. the space an account and its fields take up in memory) regularly. An account can, however, be made rent-exempt if its balance is higher than some threshold that depends on the space it's consuming
If an account has no balance left, it will be purged from memory by the runtime after the transaction (you can see this when going navigating to an account that has been closed in the explorer)
"closing" instructions must set the data field properly, even if the intent is to have the account be purged from memory after the transaction
In any call to a program that is of the "close" kind, i.e. where you set an account's lamports to zero so it's removed from memory after the transaction, make sure to either clear the data field or leave the data in a state that would be OK to be recovered by a subsequent transaction.
Solana has sysvars that are parameters of the Solana cluster you are on. These sysvars can be accessed through accounts and store parameters such as what the current fee or rent is. As of solana-program version 1.6.5, sysvars can also be accessed without being passed into the entrypoint as an account.
Escrow Program Overview
Flow
Account Relations
Part 1
Fisrt, let's create a new project solana-escrow
:
Next, we update the Cargo.toml
manifest to as follows:
According to the program architecture, we will have five modules in the end. Let's create all these files at once before we start implementing them.
Next, define these modules in lib.rs
:
Let's begin to implement these modules. First, we define instructions. Instructions are the APIs of program. Copy and paste the following snippet into your local instuction.rs
:
You may notice that there are a few compile warning telling you InvalidInstruction
is not resolved. Let's implement it in error.rs
.
Update dependencies:
Update error.rs
:
The main business logic locates in processor.rs
. There will be two functions corresponding two instructions. Let's implement those one by one. Here we implement the process_init_escrow
function which matches EscrowInstruction::InitEscrow
case:
Update dependencies:
Update processor.rs
:
Part 2
You will notice a warning raised due to unresolved state::Escrow
.
What does state.rs
do? It basically represents the data structure stored in the account owned by Escrow program. Also, it has the pack/unpack utils to convert the data format.
Update dependencies:
Update state.rs
:
Let's further extend the business logic of process_init_escrow
in processor.rs
:
Here, we can see invoke
is called to perform a CPI.
To make the first function process_init_escrow
callable, let's put it in the entrypoint.rs
:
Check if we can compile it successfully:
Part 3
Next, we can implement another instruction Exchange
and its corresponding function process_exchange
.
Update instruction.rs
:
Also in processor.rs
:
Here we can see that invoke_signed
is called with seeds since the owner of escrow account is a PDA.
Finally, implement the missing error enums:
Check if we can compile successfully:
Interact with the escrow program
See this repo for more details
Basic setup
Now, we can write some client side code to interact with the escrow program.
First, let's install dependencies:
Next, let's generate the files to be filled in necessary code and data:
Generate Keypairs
We have to generate keypairs for alice
, bob
, and the transaction payer
. This can be done via solana-keygen
:
Next, we need to manually update the public keys for each. Retrieve the address for all of them and paste it to the *_pub.json
files accordingly. For example:
Don't forget the double quotes
Add Code Base
Here we add the client code base. Copy and paste the following files to your local code base:
Again, I strongly recommend you to clone the original code base and run it
Compile, Depoly and Setup
First, let's start the validator:
Compile and deploy the program:
Before we execute the client code, we need to update the programId
to be looked up:
Also, update the predefined terms.json
as follows:
Fund the transaction payer
in advance:
Run the Client Code
Finally, let's run the client code:
First, run setup.ts
to mint the tokens to be exchanged:
Next, run alice.ts
to initialize the escrow program:
You can see how an instruction is constructed. The interger 0
assined to the Uint8Array
represents the instruction InitEscrow
:
Then, run bob.ts
to exchange and close the escrow account:
3. Escrow Program (using Anchor)
Goal
Learn the best practice
Why use Anchor?
Remove Boilerplate
Make Solana program safer
Clearer code structure
A good framework reduces the mental pressure and keep the precious attention resource to important things
I actually wrote another post explaining the whole thing. See this doc to learn more.
More Advanced Topics
Solana Program Library
...
References
General
https://medium.com/@asmiller1989/solana-transactions-in-depth-1f7f7fe06ac2
https://hackmd.io/@adamisrusty/HkVyZHBoO
https://2501babe.github.io/posts/solana101.html
https://github.com/paul-schaaf/awesome-solana
https://github.com/project-serum/awesome-serum
https://solana.com/developers
Front-End Development
https://github.com/yihau/full-stack-solana-development
https://github.com/yihau/solana-web3-demo
https://github.com/raydium-io/raydium-ui
https://github.com/thuglabs/create-dapp-solana-nextjs
Program Development
https://paulx.dev/blog/2021/01/14/programming-on-solana-an-introduction/#instruction-rs-part-1-general-code-structure-and-the-beginning-of-the-escrow-program-flow
https://github.com/jstarry/solana-workshop-tw
https://jstarry.notion.site/Program-deploys-29780c48794c47308d5f138074dd9838
https://jstarry.notion.site/Transaction-Fees-f09387e6a8d84287aa16a34ecb58e239
Anchor Tutorials
https://hackmd.io/@ironaddicteddog/anchor_example_escrow
https://github.com/ironaddicteddog/anchor-escrow
https://github.com/ironaddicteddog/anchor-amm
https://dev.to/dabit3/the-complete-guide-to-full-stack-solana-development-with-react-anchor-rust-and-phantom-3291
https://2501babe.github.io/posts/anchor101.html
https://www.brianfriel.xyz/learning-how-to-build-on-solana/
https://project-serum.github.io/anchor/tutorials/tutorial-0.html
Core Technology
https://medium.com/solana-labs/proof-of-history-explained-by-a-water-clock-e682183417b8
https://medium.com/solana-labs/proof-of-history-a-clock-for-blockchain-cf47a61a9274
https://medium.com/solana-labs/sealevel-parallel-processing-thousands-of-smart-contracts-d814b378192
https://medium.com/solana-labs/solanas-network-architecture-8e913e1d5a40
https://medium.com/solana-labs/7-innovations-that-make-solana-the-first-web-scale-blockchain-ddc50b1defda
https://jito-labs.medium.com/solana-validator-101-transaction-processing-90bcdc271143
Twitters
https://twitter.com/ironaddicteddog
https://twitter.com/armaniferrante
https://twitter.com/therealchaseeb
https://twitter.com/jstrry
Last updated