Table of contents
๐ฅ What skills will I upload to you?
When I started a few months ago, the most challenging part was not learning how to build on Ethereum, Solana, or Blockchain Z but instead grasping the flow and concepts of working with Blockchains. This article is what I wished someone had done for me in the beginning: let me look over their shoulder and see something happening, instead of talking about Proof of Work, Proof of Stake, etc. Let me experience it first!
If you come from Ethereum jump directly to blog.mwrites.xyz/your-first-solana-program#.. Ethereum
Every blockchain has its forte and does things differently, but guess what? They are all Blockchains, and they have stuff in common, so we will:
- ๐ญ Taste the difference between working with a Blockchain VS traditional Web Services.
- ๐งพ Learn the language of Blockchains: Transactions and Instructions.
- ๐ช Understand how to store data in Solana.
- ๐ Ship your first Solana Program!
- ๐ฆ Optional: Complete the circle by making a frontend app to talk to your program.
TLDR: Try it live! Fullstack code here
๐ Enter Joke To Earn!
In this tutorial, we will create a Program on the Solana Blockchain to let people read and send jokes, but instead of storing the data on a server, we will be using the Solana Blockchain.
๐จ๐ปโ๐ซ Smart Contract One Oh One
So what is a Program?
A Program (or a Smart Contract in Ethereum) is just some code that will be living and run by the Blockchain.
And what is a Blockchain?
Without writing a whole white paper about it, a Blockchain is just a public database for our interest.
-> In a traditional web2 stack, you had your server and database living on Google Cloud, AWS, etc.
-> In a web3 paradigm, we deploy our code and store data on a public and distributed database that belongs and can be used by everyone! That is a very simplified way of seeing a Blockchain, but in our context of writing a smart contract, that is enough for us to understand.
So here you have it, a Solana Program or a Smart Contract is a piece of code running on a distributed database.
Momentum! Not Textbooks
There are so many things to learn in Blockchains! Not to mention the specifics about each blockchain. If you had to learn Blockchain from the bottom up, you would get into a rabbit hole, so instead, we will focus on getting sh*t done!
I won't explain every keyword or detail but instead, focus on what is happening and the flow of things.
Once you get the feel of how things work, I recommend you dive deeper and, little by little, look behind the curtains. I will create a series to dive deeper into HOW Blockchains work later.
โ๏ธ Anchor the boat
We will be using Anchor to develop our first Solana Program. Anchor is a framework to develop Solana Programs. It removes tons of the boilerplate code you would write if you just used bare bone Rust with Solana. Oh yes, by the way, Solana Programs are written in Rust.
๐ป Installing Stuff
Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
rustup component add rustfmt
Install Solana
A) The build tools evolve quickly, on M1 you might run into an issue when using solana-test-validator
or other obscure build issues later. So, install and build Solana from source following the instructions of the official doc or even the github which is often more up to date.
B) If you are not on an Apple M1:
sh -c "$(curl -sSfL https://release.solana.com/v1.9.5/install)"
Depending on your system, the end of the installer messaging may prompt you to modify your path, just follow the instructions.
Install Node and NPM with NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install node
Install Yarn
npm install -g yarn
If you already have npm installed via brew or nvm, I suppose you know what you are doing, so just get yarn installed the way you like.
Why do we even need Yarn? Isn't it for JavaScript? Indeed Sir/Madam! Anchor needs it to test our Solana Programs using NodeJS; this will be useful for using our Program.
Install Anchor
cargo install --git https://github.com/project-serum/anchor anchor-cli --locked
Let's make sure everything is installed correctly; otherwise, you might end up with incomprehensible errors later, such as the dreaded error: no such subcommand: build-bpf
if you have no idea what I am talking about, just know that I suffered ๐
(Copy paste the whole thing in your terminal)
solana --version
rustup --version
rustc --version
cargo --version
yarn --version
๐ฌ Init
Set Solana to use localhost instead of a real Blockchain
solana config set --url localhost
Init the project
export proj=joketoearn
anchor init $proj
cd $proj
๐ Your first Program
I will be using โ๏ธ emoji when we implement the Solana Program and ๐งข when we are trying to call that program like a frontend app.
โ๏ธ Implement the Solana Program using Anchor
Since we are creating a social joke app, let's add a function to send jokes.
Open programs/joketoearn/src/lib.rs
and copy-paste this instead of the boilerplate code:
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod joketoearn {
use super::*;
pub fn create_joke(ctx: Context<CreateJokeCtx>, joke_content: String) -> ProgramResult {
msg!("joke_content: {}", &joke_content);
Ok(())
}
}
#[derive(Accounts)]
pub struct CreateJokeCtx {}
โ ๏ธ Your declare_id must be different than mine; just use yours if it differs.
This is not a Rust Tutorial, nor do we want to learn all the keywords as they constantly evolve with the frameworks, but here are the essential pieces:
declare_id
is the id/address of your program; why do you need an id? Well, since your program lives in communion with other programs on the blockchain, we need a way to identify your program.- We define our
create_joke
function, which takes ajoke_content: String
and prints it withmsg!
- Every function we create in Anchor needs that first argument
ctx: Context<>
, it is a way to tell Anchor what metadata we need for our function; we will see later below how to use it.
๐งข Put on your frontend cap, let's try the Program
Ok, let's try to call our Program. Instead of implementing a frontend app, we can leverage the tests that Anchor has set up for us. Earlier, we installed JavaScript libraries, now is the time to use them; Anchor set up for you a NodeJS app to use as a client.
When running anchor test,
this is not just a unit test; this will actually:
- Spin up a local Solana Blockchain Node.
anchor build
+anchor deploy
your program on it.- Run the tests.
So the workflow is similar to how you would be calling your Solana Program from a client such as an iOS or a frontend app or even a traditional backend service. The tests will help us skip all the front-end setup we would have to do otherwise.
Let's implement the tests, jump to tests/joketoearn.ts
and replace the content with:
import * as anchor from '@project-serum/anchor';
import { Program } from '@project-serum/anchor';
import { Joketoearn } from '../target/types/joketoearn';
describe('joketoearn', () => {
anchor.setProvider(anchor.Provider.env());
const program = anchor.workspace.Joketoearn as Program<Joketoearn>;
it('It Creates a Joke!', async () => {
const tx = await program.rpc.createJoke('Not funny..');
console.log("Your transaction signature", tx);
});
});
๐จ๐ปโ๐ณ Here's the recipe to call a blockchain Program
- Get a connection to a Blockchain.
- Reference the Program you want to talk to.
- Call the function on the Program.
1. Connecting to a Blockchain
Provider
is a helper to provide a connection to a Blockchain.
-> Remember? Your code is deployed on the Blockchain, and where is that Blockchain? There are different endpoints for each environment, your localhost, testnet, staging, mainnet (production), etc. In our case, it defaults to localhost.
2. Get our Program
Ok, we are connected to the localhost Blockchain Node; now we need to get a hand on our program; why can't we just call a URL like 127.0.0.1:3000/create_joke
?
-> Well, because your program is not exposed on the Internet directly, it lives inside the Blockchain. Also, Blockchain Node does not only run your program; you share the processing power with other people's Programs. So we need to specify to the Blockchain which Program we want to talk to.
-> For the tests, Anchor already did that for us const program = anchor.workspace.Joketoearn,
but you will need to use the Program Address that we declared with declare_id in an actual client.
3. Remote Procedure Call
Finally, we do a Remote Procedure Call, note that our function create_joke
has been renamed createJoke
So run those tests!
anchor test
Check the logs
cat .anchor/program-logs/Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS.joketoearn.log
๐ง๐ง๐ง Transactions? Instructions? Signatures?
In the Blockchain world, we do not call functions, we craft instructions, and we send those instructions to Solana programs, in that case, Solana System Program.
๐ฅณ REPHRASED: in The blockchain world, we do not call functions or APIs directly, we craft transactions ๐ which instruct ๐ the Solana runtime on what to do. We also stamp โ๏ธ these letters to prove that we paid for posting ๐ฌ that letter.
A transaction is just a list of instructions; in our case, it does not matter since we will only send one instruction at a time.
It sounds like having a Super Assembler Program on the Internet, where we would instruct that Shared Assembler Program to do stuff.
ERRATA: Initially when I wrote the article, I thought there was a concept of hierarchy between the SystemProgram and the other programs. This is WRONG, SystemProgram is just another program like others.
๐ Creating Jokes
โ๏ธ Anchor side
All right, we know how to talk to Solana, nice. Now that communication basics are out of the way let's tackle creating these jokes.
Let's define a data structure for it where we will keep:
- The author of the joke.
- The actual joke.
Getting the Author's public key
How can we identify the author of the Joke? If it were a typical back-end tutorial, we would talk about boring stuff like registering a user's email and password, sending him a confirmation email, etc. HELL NO.
So how do we get the user identifier if we haven't created a user yet?
In web3, users connect to the blockchain using a Wallet App such as Metamask or Phantom. So there is no need to create a user; they already have a user id (ahem.. I mean user public address), we just ask for it.
If we think about the UX, it is similar to OAuth, where the user would authenticate with a Wallet App instead of Twitter or Google.
๐ง What are Wallets?
Like the traditional apps where we need to log in, you need to be authenticated in the Blockchain world every time you do something. But, in Blockchain, we don't use logins and passwords; we use a signature โ๏ธ. And a wallet provides a way to stamp/sign.
Instead of having a dozen user accounts with Google, Twitter, etc.. you have one identity, that identity, that pen, that signature, that stamp sits with you and be used everywhere. You show the gatekeepers your pen, your signature, the chain acknowledges your identity, and boom, welcome to web3 land!
By the way, you can also create multiple wallets if you want various identities.
One important thing, that you we can think about later, is that connecting a wallet is not exactly like a sign in. Why is that? When we connect a wallet we just give a publicKey, you could give anyone's publicKey it does not proves that it is your publicKey. That is why, an additional step is required in some dapps like OpenSea, where they will ask you to sign a message to actually prove that you own the publicKey.
Source: @haltakov.eth
๐คทโโ๏ธ Why Wallets?
Now you are thinking; we were just fine with user accounts. Who had the bizarre idea to create wallets, and why do you even care? If you want to know more about wallets, please check out this post: blog.mwrites.xyz/why-do-we-need-wallets-in-...
โ๏ธ Ask Anchor for the Author of the Transaction
Remember? When the user call our create_joke
function he is doing a transaction. Modify the CreateJokeCtx
:
#[derive(Accounts)]
pub struct CreateJokeCtx<'info> {
pub authority: Signer<'info>,
#[account(address = anchor_lang::solana_program::system_program::ID)]
pub system_program: AccountInfo<'info>
}
authority: Signer
: Authority is how we identify who thecreateJoke
transaction's signer. Why is the typeSigner
while we definedauthor: PubKey
in our struct? This is a hint to Anchor to verify that the givenPubKey
is not only a PubKey but also theSigner
of the transaction, the person who signed and paid for it.- We also need the
system_program.
I am not very sure why Solana cannot find ITSELF!๐น But in all implementations that I have seen, this was required. (I will update if I know more about this) - Lastly, don't worry about all the
account
keywords for now. This will come later.
Still in Anchor, modify create_joke
:
pub fn create_joke(ctx: Context<CreateJokeCtx>, joke_content: String) -> ProgramResult {
msg!("joke_content: {}", &joke_content);
let pubkey = &*ctx.accounts.authority.key.to_string();
msg!("pubkey: {}", pubkey);
Ok(())
}
๐งข Frontend side, modify the tests
Modify tests/joketoearn.ts
it('It Creates a Joke!', async () => {
const tx = await program.rpc.createJoke('Not funny..', {
accounts: {
authority: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
//signers: [program.provider.wallet],
});
console.log("Your transaction signature", tx);
});
- Take note of wallet.publicKey
, this is the user's wallet public address; you don't need to add it in the
signers: []` list because Anchor will do that automatically for you. systemProgram,
as we said earlier, is necessary; it is Solana Master Program.
Test it:
anchor test
Check the logs
cat .anchor/program-logs/Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS.joketoearn.log
You should see
Program log: joke_content: Not funny..
Program log: pubkey: 5EsbC1VEAKY2qaFp6aszcXrf8VYQnjFZRWTGiGdzyBfK
๐ง IDLs
At this point, you might be asking... All of this is mysterious and magical. I keep throwing code at you, but how are you supposed to know what our Program looks like from the frontend side? Here's a secret ๐คซ, after every anchor build
or anchor test,
an IDL (interface description language) will be produced. That file describes what our Program API looks like; it's here target/idl/joketoearn.json
{
"version": "0.1.0",
"name": "joketoearn",
"instructions": [
{
"name": "createJoke",
"accounts": [
{
"name": "authority",
"isMut": false,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "jokeContent",
"type": "string"
}
]
}
],
"metadata": {
"address": "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
}
}
- Our
createJoke
is an instruction and expects something calledaccounts
. - Note the
metadata.address
which is the address of our Program.
Another nicety of Anchor tests is that we don't need to care about this, but if you build your front-end, you will have to fetch that IDL so that the frontend knows how to call your Program. I will show how to do this in the front-end part.
๐ Storing and Passing data with Accounts
๐งพ A world of Accounts
It's time to reveal the truth ๐ค. I have been hiding this all along, but everything is about these mysterious accounts. You are ready to know.
The translation of our Program into an IDL proves it; our createJoke
instruction expects an array of accounts
:
"instructions": [
{
"name": "createJoke",
"accounts": [
{
"name": "authority",
"isMut": false,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
}
],
...
It expects an array of accounts because we told Anchor to #[derive(Accounts)]
from the CreateJokeCtx
Instruction Context
pub fn create_joke(ctx: Context<CreateJokeCtx> ...)
#[derive(Accounts)]
pub struct CreateJokeCtx<'info> {
...
}
๐ So what are these Accounts?
In Solana, Programs are stateless; they store data separately into what we call "Accounts."
โ ๏ธ I was confused initially, but keep that in mind, it is a faux-ami (fake friend in french). It is not what you think, and it is not a traditional email/password/user, etc...
As described by the Official Doc:
Accounts are similar to files in operating systems such as Linux in that they may hold arbitrary data that persists beyond the lifetime of a program.
So an account is just how Solana deals with data on the chain. It is just a buffer of bytes, and there are some rules to encode data properly into that buffer of bytes.
โ๏ธ Save the Joke as an Account
So hopefully, Anchor is here to the rescue and has been helping us with all these weird #
macros. Let's add a struct and define it as an #[account]
so that Anchor can handle our struct's proper serialization/deserialization into an account shape.
Below pub struct CreateJokeCtx
add this:
#[account]
pub struct Joke {
pub author: Pubkey, // this is the authority we worked so hard to get earlier
pub content: String,
}
Create space for the Joke Account We have defined our struct, but we still haven't done anything to materialize that data. In Web2, we would:
- Create the struct.
- Save that to the DB.
- End of story.
Web3 glasses ON ๐ค, we have a few things to consider. To save our struct, we need to tell Solana:
- How much space do we want in the blockchain -> Remember? We are using "public goods" so we can't use as much space as we want.
- Who is going to pay for it (not me) -> Same as above, "public goods" = we are renting the space.
- Who owns that data? Yes, you heard the data can be owned by the user, data to the people!
Modify CreateJokeCtx
:
#[derive(Accounts)]
pub struct CreateJokeCtx<'info> {
#[account(init, payer = authority, space = 2000)]
pub joke_account: Account<'info, Joke>,
#[account(mut]
pub authority: Signer<'info>,
#[account(address = anchor_lang::solana_program::system_program::ID)]
pub system_program: AccountInfo<'info>
}
Explanation:
#[account(init, payer = authority, space = 2000)]
pub joke_account: Account<'info, Joke>
Ok, these two lines are proper to Anchor. What they mean under the hood is:
- Tell Solana how much space our joke struct represent as an account.
- Tell who will pay for that space, here the authority field (told you not me, so the signer of the transaction).
- Ask Solana to materialize that space.
- Serialize and Deserialize the account, an array of bytes into something usable for us: the joke
struct
.
Lastly note the additional #[account(mut)]
above authority
#[account(mut)]
pub authority: Signer<'info>
This says that the transaction create_joke
should be allowed to mutate the signer's account. Why? Because we need to make users pay for the space allocated for the joke and deduct sol from their Wallets ๐ฅณ.
So we can finally modify our create_joke
function to:
pub fn create_joke(ctx: Context<CreateJokeCtx>, joke_content: String) -> ProgramResult {
let joke: &mut Account<Joke> = &mut ctx.accounts.joke_account;
joke.author = *ctx.accounts.authority.key;
joke.content = joke_content;
Ok(())
}
โ ๏ธ space = 2000
You need to figure out how much space you need to store as the price is relative to the space you are creating. For our tutorial, it does not matter, but you should definitely modify this if you deploy on the MainNet chain as users will pay real sol.
**Another paradigm of web3 is that you need to pay to store your data. In web2, you used to pay your web server or whatever provider you were using, or maybe they provided everything for free!
In web3, we are storing our data to the public blockchain, so we need to pay rent to store that data. Also, what does it mean to own your data? Here it means that only the user can modify the data, so we need a way to manage permissions for data.
๐งข Final jump to the other side
Create an account
So from the other side, what does our program need?
It needs an account for our jokeAccount
; look at what we did for the authority
and systemProgram
accounts previously. Solana can find an account using its public address.
Remember, remember, remember: Accounts are... ๐ฅ๐ฅ just like files or ๐ฆ to store data.
So Solana was looking for the boxes of the user wallet and the systemProgram by using SystemProgram.programId
and wallet.publicKey
:
const tx = await program.rpc.createJoke('not funny..', {
accounts: {
jokeAccount: something.publicKey???,
authority: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [something],
});
However, SystemProgram and the user wallet already exists on the chain; that is why Solana can find those by their public addresses. In our case, the account does not exist yet but will be created from our program. Remember? We just defined space etc., above. So what we need to do here is not to create an account but rather create an address for the account:
it('It Creates a Joke!', async () => {
// Create an address for the soon-to-be created Account
const jokeAccountKeypair = anchor.web3.Keypair.generate()
// Craft the createJoke Instruction
const tx = await program.rpc.createJoke('Not funny..', {
accounts: {
jokeAccount: jokeAccountKeypair.publicKey,
authority: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [jokeAccountKeypair]
});
console.log("Your transaction signature", tx);
});
Speaking of accounts, have you noticed that systemProgram also goes into accounts? Programs and Solana System Program is an account! Programs are stored as read-only accounts on the chain.
If you are curious about the additional
signers
, read the Going Further section later.
๐๐พ The Grand Final in 1 minute
Cool, but we have been working in the dark. It would be nice to retrieve the data to see that it works and start passing it to other jokesters.
The good news is we don't have to create another function in our Solana Program, nor do we have to pay!
In your tests tests/joketoearn.ts
๐งข, just add this to fetch data from all jokes accounts:
...
console.log("Your transaction signature", tx);
// Fetch all joke accounts
const jokes = await program.account.joke.all();
console.log(jokes);
anchor test
๐คฉ And voila!
๐ Recap
Congrats!! ๐
It was not a fast tutorial, but at least now, you acquired new skills and understood the client/blockchain flow. You learned the difference between working with a Blockchain compared to traditional web services, you spoke in Transactions instead of REST APIs, you grasped the idea of signing, you got horrified by the idea of paying for space and transactions. ๐คฃ
These, my friend, are skills that you can re-apply to any blockchain. If you want to dive deeper into Solana, you can follow the Solana Series on my blog. There are also other very cool tutorials here:
- lorisleiva.com/create-a-solana-dapp-from-sc..
- buildspace.so/learn-solana
- dev.to/dabit3/the-complete-guide-to-full-st..
The final code is here: https://github.com/mwrites/solana-JokeToEarn Live example here: https://solana-joke-to-earn.vercel.app
As you get comfortable with Anchor, you should see how Solana does things directly. Anchor is just some Sugar that reduces some code, and if you want to dive deeper, you should also understand what Anchor is doing for you. You can take a look at solanacookbook.com and compare it to your Anchor code.
By the way, Solana is not the easiest Blockchain. Rust and Accounts are a bit more involved. Ethereum developer tools are more mature, and Solidity is simpler to write. But both ecosystems are as exciting, and with time and as more people come in, Solana will evolve as well.
And finally, don't think about web3 > web2
; a blockchain is just a new tool in your toolbox, a new way of doing things. From a tech perspective, look at the ecosystem being built and the cultural and social changes that these new applications will enable.
Cheers ๐ป
๐ Next
We will complete the circle with the frontend so you can have the full-stack DApp:
- We will deploy our Program to a real Solana Chain.
- We will make a simple frontend app to talk to our Program.
- We will see how the UX work with a Wallet App and start signing and paying for transactions (you still haven't paid anything because we were using ancor tests ๐)
๐ฑ Going Further (come back here after you uncharged your brain on love island )
Talking to other people's Programs!
const data = await program.account.ACCOUNT_NAME.all();
This means you can fetch data from any Solana Program deployed on the chain; for that, you would need its IDL:
First, get;
The Program Address of the program you are trying to talk to.
The idl of the program to know what the program looks like, you can fetch the idl with.
anchor idl fetch PROGRAM_ADDRESS
Program Addresses are public! Teams and Projects are encouraged to publish their addresses. Since your code is on the public Blockchain anyway, there is no need to hide it. It opens up so many possibilities.
Can you think about any? I would love to hear your thoughts below!
For example, here's how to get the contract for one of my pet projects: vercel.com/matanwrites/w3-solana-thumbs-up
anchor idl fetch EGWf3mBuwhvjmR134QfzKGMo8EgtsC4ieMP3D6mxWFXq --provider.cluster devnet
Why did we need the additional jokeAccountKeypair
as a Signer?
it('It Creates a Joke!', async () => {
// Create an address for the soon-to-be created Account
const jokeAccountKeypair = anchor.web3.Keypair.generate()
// Craft the createJoke Instruction
const tx = await program.rpc.createJoke('Not funny..', {
accounts: {
jokeAccount: jokeAccountKeypair.publicKey,
authority: program.provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
},
signers: [jokeAccountKeypair]
});
console.log("Your transaction signature", tx);
});
To understand that, let's look at what happens in our Solana Program, with
#[account(init, payer = authority, space = 2000)]
pub joke_account: Account<'info, Joke>,
- Make the authority (wallet.publicKey) pay; anchor automatically added the user wallet as a signer.
- Once this is paid, materialize an account and set his address to...
- ...To the
jokeAccount: jokeAccountKeypair.publicKey
Now, let's say you are the user, and instead of creating a new jokeAccountKeypair
, you replaced it with lauraJokeAccountKeypair
. What would happen would be that:
- You will pay for the account.
- The Program will materialize the account and set his address to...
- ...To laura's jokeAccount! So you will be overriding her joke, basically ๐ .
That is why it is crucial to make sure the account's public address is owned by you also, and you prove that by providing the privateKey to that publicKey address.
Are you ready to checkout?
It's time to pay, literally. Another paradigm of web3 is that you need to pay to store your data; in web2, you used to pay your web server or whatever provider you were using, or maybe they provided everything for free! In Web3, we store our data in the public domain, so we need to pay rent to store that data, so let's do that. We need to ask Solana to lend us some land!
Let's see what the market prices are:
Open a new Terminal and run a local ledger:
solana-test-validator
Back to your main terminal, check the rent for 2kb of data:
solana rent 2
Rent per byte-year: 0.00000348 SOL
Rent per epoch: 0.000002477 SOL
Rent-exempt minimum: 0.0009048 SOL
There is a simple solution that everyone is currently going for, instead of regularly paying per epoch, if you spend enough for two years of rent, you are good for life: docs.solana.com/implemented-proposals/rent#...
twitter.com/jacobvcreech/status/15226175264..
A Must Read For Solana Devs
twitter.com/armaniferrante/status/148388965..
WTF Solana?
In construction
Solana errors can be found here: github.com/solana-labs/solana-program-libra..
๐ Review & EVM Comparison
The Consequence Of Accounts
You might notice that the Solana version is much more involved. If we can resume it in one word, that word is Accounts. You might have seen the phrase " Solana programs are stateless". It took me a while to really, I mean, really understand what this involves. Basically, it means programs are dumb!
So, programs don't know anything. They are just machine processing data. So when you want to talk to programs, you want them to process something. But they have no idea what data you are talking about, so because of that, you need to always provide everything to these processors:
- The first consequence of this is that data (accounts) need to be provided with each instruction, which makes the code longer to write.
- The second consequence is that because accounts are independent of programs, they need to be signed for access control, which again makes the code longer to write.
It's not just program->accounts, it's program->accounts->signer
Because of these two reasons, accounts introduce a new depth. For example, when you want to talk to a program, you want to give an account and not only the account but also the account's signer. So whenever you want to do something, you first need to get the accounts and make sure you have the appropriate signing in place. Then, finally, you can do something with the account.
Rent
Finally, we need to pay rent for the space accounts occupied in Solana. The rent is usually paid by the signer of the transaction. Because space needs to be paid, we are incentivized as developers to make accounts are small and granular as possible.