mwrites
Web3 Cartographer

Web3 Cartographer

BUIDL a Solana Program - Explain me like I am web2

BUIDL a Solana Program - Explain me like I am web2

mwrites's photo
mwrites
ยทJan 21, 2022ยท

22 min read

Subscribe to my newsletter and never miss my upcoming articles

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:

  1. ๐Ÿญ Taste the difference between working with a Blockchain VS traditional Web Services.
  2. ๐Ÿงพ Learn the language of Blockchains: Transactions and Instructions.
  3. ๐Ÿช Understand how to store data in Solana.
  4. ๐Ÿš€ Ship your first Solana Program!
  5. ๐Ÿฆ„ 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.

intro-gif.gif

๐Ÿ‘จ๐Ÿปโ€๐Ÿซ 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.

blockchain_vs_web2.png

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 a joke_content: String and prints it with msg!
  • 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:

  1. Spin up a local Solana Blockchain Node.
  2. anchor build + anchor deploy your program on it.
  3. 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

  1. Get a connection to a Blockchain.
  2. Reference the Program you want to talk to.
  3. 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

anchor_test_create_joke_1.png

Check the logs

cat .anchor/program-logs/Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS.joketoearn.log

anchor_test_create_joke_1_logs.png

๐Ÿง๐Ÿง๐Ÿง 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.

create_joke_transactions_1.png

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:

  1. The author of the joke.
  2. 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.

Screen Shot 2022-02-03 at 7.54.28 PM.png

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 the createJoketransaction's signer. Why is the type Signer while we defined author: PubKey in our struct? This is a hint to Anchor to verify that the given PubKey is not only a PubKey but also the Signer 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);
});
  1. Take note of wallet.publicKey, this is the user's wallet public address; you don't need to add it in thesigners: []` list because Anchor will do that automatically for you.
  2. systemProgram, as we said earlier, is necessary; it is Solana Master Program.

transaction_sign.png

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 called accounts.
  • 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:

  1. Create the struct.
  2. Save that to the DB.
  3. End of story.

Web3 glasses ON ๐Ÿค“, we have a few things to consider. To save our struct, we need to tell Solana:

  1. 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.
  2. Who is going to pay for it (not me) -> Same as above, "public goods" = we are renting the space.
  3. 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:

  1. Tell Solana how much space our joke struct represent as an account.
  2. Tell who will pay for that space, here the authority field (told you not me, so the signer of the transaction).
  3. Ask Solana to materialize that space.
  4. 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

anchor_test_fetch_jokes.png

๐Ÿคฉ 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:

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:

  1. We will deploy our Program to a real Solana Chain.
  2. We will make a simple frontend app to talk to our Program.
  3. 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 ๐Ÿ˜ˆ)

Let's do it!


๐Ÿ˜ฑ 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;

  1. The Program Address of the program you are trying to talk to.

  2. 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>,
  1. Make the authority (wallet.publicKey) pay; anchor automatically added the user wallet as a signer.
  2. Once this is paid, materialize an account and set his address to...
  3. ...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:

  1. You will pay for the account.
  2. The Program will materialize the account and set his address to...
  3. ...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#...

image.png twitter.com/jacobvcreech/status/15226175264..

A Must Read For Solana Devs

image.png 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:

  1. The first consequence of this is that data (accounts) need to be provided with each instruction, which makes the code longer to write.
  2. 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.


References

Did you find this article valuable?

Support mwrites by becoming a sponsor. Any amount is appreciated!

Learn more about Hashnode Sponsors
ย 
Share this