Developing for Solana Blockchain

Rahul Ravindran

Overview

In this article you’ll learn about some of the very high level topics related to Solana development such as: development workflows, programs, dApps (decentralized application), and client SDKs that will give you a clear path to developing on Solana. This article is intended for developers that are new to Solana and assumes you already have some general knowledge around blockchain development for things like dApps, Smart Contracts and tokens. If all of this makes sense then this article is definitely for you. Now let’s get started!

Solana Workflow

Solana smart contracts are written in Rust but you aren’t required to know Rust or understand on-chain programs to build on Solana, although once you’re comfortable with building dApps you’ll likely want to learn how to create your own contracts and learn more about the Rust programming language. On Solana, and most smart contract blockchains, there are two completely different development workflows:

Smart Contract Development

Smart contracts are programs built and deployed on-chain and are run via the Solana Runtime where they live forever. These programs can be used by anyone who knows how to communicate with them by submitting transactions with instructions to the network via the JSON RPC API or any SDK built on top of this API. Other on-chain programs can also make use of the JSON RPC API.

Dapp Development

dApp development is something that most web 2 and web 3 developers will be more familiar with. This type of development involves creating applications that send transactions with instructions to on-chain programs and very closely resembles building web/mobile apps and interacting with centralized APIs. The foundation of app development on Solana is the JSON RPC API which is a layer of communication that allows you to interact with the blockchain. Solana Labs has created an easy to use solana-web3.js SDK that allows you to talk to the blockchain and Solana programs in a way that feels just like talking to any other API you’ve used. There are many 3rd party SDKs that have also been built on top of the JSON RPC API such as Java, C#, Python, Go, Swift, Dart-Flutter and Kotlin. You can access these SDKs on the Solana Developers Page.

Each of these SDKs gives you the power to build fully functional dApps on Solana in your favorite languages. Once you’ve mastered the Solana API you can then start to understand how to build your own programs in Rust, C or C++.

Starting at the top left of the diagram (Program) you can see the first development workflow that allows you to to create and deploy custom Rust, C and C++ programs directly to the blockchain. Once these programs are deployed, anyone who knows how to communicate with them, can use them. You can communicate with these programs by writing dApps with any of the available client SDKs (or the CLI), all of which use the JSON RPC API under the hood.

The second development workflow is the dApp side starting on the bottom left (Client) where you can write dApps that communicate with deployed programs. Your apps can submit transactions with instructions to these programs via a client SDK to create a wide variety of applications such as wallets, DEXs and more. These two pieces work together to create a network of dApps and programs that can communicate with each other to update the state and query the blockchain.

Developers can think of Solana as a global computer where anyone in the world can deploy programs to it, and communicate with the ones that already exist.

Your first Smart Contract

We are building a simple smart contract that greets with a Hello World message whenever its invoked. We will also look at another feature which will keep track of total hello world messages sent to understand how state is persisted in the block chain. Please follow along with the source code here

The following dependencies are required to build and run this example, depending on your OS, they may already be installed:

If this is your first time using Rust, these Installation Notes might be helpful.

Configure CLI

If you’re on Windows, it is recommended to use WSL to run these commands

  1. Set CLI config url to localhost cluster
    solana config set --url localhost
  2. Create CLI Keypair

If this is your first time using the Solana CLI, you will need to generate a new keypair:

solana-keygen new

Start local Solana cluster

This example connects to a local Solana cluster by default.

Start a local Solana cluster:

solana-test-validator

Note: You may need to do some system tuning (and restart your computer) to get the validator to run

Listen to transaction logs:

solana logs

Install npm dependencies

npm install

Our first simple smart contract

// Program entrypoint's implementation
pub fn process_instruction(
    program_id: &Pubkey, // Public key of the account the hello world program was loaded into
    accounts: &[AccountInfo], // The account to say hello to
    _instruction_data: &[u8], // Ignored, all helloworld instructions are hellos
) -> ProgramResult {
    msg!("Hello World Rust program entrypoint");

    // Iterating accounts is safer then indexing
    let accounts_iter = &mut accounts.iter();

    // Get the account to say hello to
    let account = next_account_info(accounts_iter)?;

    // The account must be owned by the program in order to modify its data
    if account.owner != program_id {
        msg!("Greeted account does not have the correct program id");
        return Err(ProgramError::IncorrectProgramId);
    }

    // Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    greeting_account.counter += 1;
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!("Greeted {} time(s)!", greeting_account.counter);

    Ok(())
}

Understanding Control Flow & Entrypoint

The client’s entrypoint does five things.

1. Establish a connection to the cluster

The client establishes a connection with the cluster by calling establishConnection.

2. Establish an account to pay for transactions

The client ensures there is an account available to pay for transactions, and creates one if there is not, by calling establishPayer.

3. Check if the helloworld on-chain program has been deployed

In checkProgram, the client loads the keypair of the deployed program from ./dist/program/helloworld-keypair.json and uses the public key for the keypair to fetch the program account. If the program doesn’t exist, the client halts with an error. If the program does exist, it will create a new account with the program assigned as its owner to store program state (number of hello’s processed).

4. Send a “Hello” transaction to the on-chain program

The client then constructs and sends a “Hello” transaction to the program by calling sayHello. The transaction contains a single very simple instruction that primarily carries the public key of the helloworld program account to call and the “greeter” account to which the client wishes to say “Hello” to.

5. Query the Solana account used in the “Hello” transaction

Each time the client says “Hello” to an account, the program increments a numerical count in the “greeter” account’s data. The client queries the “greeter” account’s data to discover the current number of times the account has been greeted by calling reportGreetings.

Our Javascript client will have 2 functions. sayHello will greet with hello along whenever its called.

export async function sayHello(): Promise<void> {
  console.log('Saying hello to', greetedPubkey.toBase58());
  const instruction = new TransactionInstruction({
    keys: [{pubkey: greetedPubkey, isSigner: false, isWritable: true}],
    programId,
    data: Buffer.alloc(0), // All instructions are hellos
  });
  await sendAndConfirmTransaction(
    connection,
    new Transaction().add(instruction),
    [payerAccount],
  );
}

reportGreetings will return the number of hello function has been called. This should give us idea about how state information is persisted in solana blockchain.

export async function reportGreetings(): Promise<void> {
  const accountInfo = await connection.getAccountInfo(greetedPubkey);
  if (accountInfo === null) {
    throw 'Error: cannot find the greeted account';
  }
  const greeting = borsh.deserialize(
    GreetingSchema,
    GreetingAccount,
    accountInfo.data,
  );
  console.log(
    greetedPubkey.toBase58(),
    'has been greeted',
    greeting.counter,
    'time(s)',
  );
}

Building the on-chain program

There is both a Rust and C version of the on-chain program, whichever is built last will be the one used when running the example.

npm run build:program-rust

Deploy the on-chain program

solana program deploy dist/program/helloworld.so

Run the JavaScript client

npm run start

Expected output

Note that public key values will differ:

Customizing the Program

To customize the example, make changes to the files under /src. If you change any files under /src/program-rust or /src/program-c you will need to rebuild the on-chain program and redeploy the program.

Now when you rerun npm run start, you should see the results of your changes.

Learn about Solana

More information about how Solana works is available in the Solana documentation and all the source code is available on github

Learn about the client

The client in this example is written in TypeScript using:

Learn about the on-chain program

The on-chain helloworld program is a Rust program compiled to Berkeley Packet Filter (BPF) bytecode and stored as an Executable and Linkable Format (ELF) shared object.

The program is written using:

Programming on Solana

To learn more about Solana programming model refer to the Programming Model Overview.

To learn more about developing programs on Solana refer to the On-Chain Programs Overview

Pointing to a public Solana cluster

Solana maintains three public clusters:

  • devnet – Development cluster with airdrops enabled
  • testnet – Tour De Sol test cluster without airdrops enabled
  • mainnet-beta – Main cluster

Use the Solana CLI to configure which cluster to connect to.

To point to devnet:

solana config set –url devnet

To point back to the local cluster:

solana config set –url localhost

Expand your skills with advanced examples

There is lots more to learn; The following examples demonstrate more advanced features like custom errors, advanced account handling, suggestions for data serialization etc:

Interesting Dapp: Break by Solana

Break is a React app that gives users a visceral feeling for just how fast and high-performance the Solana network really is. Can you break the Solana blockchain? During a 15 second play-though, each click of a button or keystroke sends a new transaction to the cluster. Smash the keyboard as fast as you can and watch your transactions get finalized in real time while the network takes it all in stride!

Break can be played on our Devnet, Testnet and Mainnet Beta networks. Plays are free on Devnet and Testnet, where the session is funded by a network faucet. On Mainnet Beta, users pay to play 0.08 SOL per game. The session account can be funded by a local keystore wallet or by scanning a QR code from Trust Wallet to transfer the tokens.

Click here to play Break

References & Next Steps

0 Comments

Leave a Reply

More great articles

How To Become a Blockchain Developer: Step-by-Step Plan

Do you want to become a become Blockchain developer? With higher salaries, reports of Ethereum Dapps becoming very successful overnight,…

Read Story

Scalable storage for your Dapps using Filecoin

Blockchain is primarily used to store state information. Storage of assets is one of the inherent problem that you as…

Read Story

Solidity Tutorial: Complete Step-by-Step Guide For Beginners 2019

In this Solidity tutorial you are going to learn how to code Solidity smart contracts by developing 5 smart contracts…

Read Story

Never miss a minute

Get great content to your inbox every week. No spam.
[contact-form-7 id="6" title="Footer CTA Subscribe Form"]
Arrow-up