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!
If you want a quick overview of how to get started, checkout our 2 min video here:
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:
- Install node (v14 recommended)
- Install npm
- Install Rust v1.56.1 or later from https://rustup.rs/
- Install Solana v1.8.2 or later from https://docs.solana.com/cli/install-solana-cli-tools
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
- Set CLI config url to localhost cluster
solana config set --url localhost
- 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 enabledtestnet
– Tour De Sol test cluster without airdrops enabledmainnet-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.
References & Next Steps
- Checkout the the guided pathway for solana development on Figment.
- Solana Developers Page
- If you’re already familiar and looking for a starter app try the dApp-scaffold
- Solana Core Concepts
Leave a Reply