Solana overview
The Solana blockchain is a proof of stake blockchain with extra sauce:
- Proof of history
- Validators use something like bittorrent to fetch blocks and don't wait for all pieces to assume correctness
- Offload data to something like filecoin so validators can run lite nodes (soon tm)
Proof of history uses a mechanism called nLocktime
that postdates transactions using block height instead of the usual timestamp.
There is no mempool, instead there is deterministic leader selection and nodes forward transactions to future leaders.
Clients declare memory locations it needs beforehand.
Multiple transactions on the same program happen in parallel with SIMD instructions. Signatures are verified on GPU's
Solana uses
ed25519
for encryptionsha256
for hashing (same hashing as bitcoin).
Much more complicated to develop on than Ethereum based chains.
Even normal SOL transfers on Solana are handled by a smart contract.
Programs written in Rust are pretty limited. Public types should be basic in general forget about custom crates, you can't even use most of std::collections
.
For example you cannot use HashMap
without modifications because by default it actually uses some sneaky thread-local static state for caching keys. Static mutable state is forbidden in Solana so it won't work.
The anchor CLI also doesn't know how to turn HashMap
into IDL. For now your easiest bet is to just use a sequence of key-value pairs unfortunately.
Solana virtual machine
The actual virtual machine responsible for executing programs is usually rBPF
. Not all validators use the same one, but that is the canonical.
The specific format is a custom version of eBPF called Solana Bytecode Format (sBPF).
eBPF was originally created to filter packets in the kernel but has applications in profiling because of its efficiency.
This bytecode is processed by a virtual machine called rBPF
. This virtual machine only has a set of 11 registers.
name | feature set | kind | Solana ABI |
---|---|---|---|
r0 | all | GPR | Return value |
r1 | all | GPR | Argument 0 |
r2 | all | GPR | Argument 1 |
r3 | all | GPR | Argument 2 |
r4 | all | GPR | Argument 3 |
r5 | all | GPR | Argument 4 or stack spill ptr |
r6 | all | GPR | Call-preserved |
r7 | all | GPR | Call-preserved |
r8 | all | GPR | Call-preserved |
r9 | all | GPR | Call-preserved |
r10 | all | Frame pointer | System register |
r11 | from v2 | Stack pointer | System register |
pc | all | Program counter | Hidden register |
You first have your General-Purpose Registers (GPRs):
r0
holds the function's return datar1
-r5
store function arguments,r5
holds "spillover" data which is represented by a pointer to some stack data.r6
-r9
are values preserved across function calls.
After that we have:
r10
the frame pointer that references the current stack frame in memoryr11
the stack pointer that keeps track of where the top of the stack ispc
the program counter that holds the address of the current instruction being executed
The virtual machine can execute eBPF programs in two ways:
- An intepreter
- Just-in-Time (JIT) compilation to
x86_64
machine code
Interpreters walk each instruction one-by-one. This adds a slight runtime overhead in exchange for a big reduction in load time.
JIT is favored as it makes the runtime execution faster at the cost of a longer load time due to the increased initial compilation.
Development cycle
The development cycle on Solana looks like this:
- Code your program in rust
- Build your program which should generate an Interface Description Language (IDL) JSON file.
- Generate a client from this IDL file
- Test the programs behavior acting as a client of the chain
These are our system specs. They test behavior from the perspective of the user with all the bells and whistles of the blockchain.
The solana-test-validator
can be used to set up a local chain to try these transactions out on and fetch the data to see if it is what we expect.