Skip to content

Latest commit

 

History

History
468 lines (339 loc) · 11.6 KB

File metadata and controls

468 lines (339 loc) · 11.6 KB
title Local Development
description Learn how to build Solana programs using the Anchor framework on your local machine.

The Anchor framework is a tool that simplifies the process of building Solana programs. Whether you're new to blockchain development or an experienced programmer, Anchor simplifies the process of writing, testing, and deploying Solana programs.

In this section, we'll walk through:

  • Creating a new Anchor project
  • Building and testing your program
  • Deploying to Solana clusters
  • Understanding the project file structure

Prerequisites

For detailed installation instructions, visit the installation page.

Before you begin, ensure you have the following installed:

  • Rust: The programming language for building Solana programs.
  • Solana CLI: Command-line tool for Solana development.
  • Anchor CLI: Command-line tool for the Anchor framework.

To verify Anchor CLI installation, open your terminal and run:

anchor --version

Expected output:

anchor-cli 1.0.2

Getting Started

This section covers the basic steps to create, build, and test your first local Anchor program.

Create a new Project

To start a new project, use the anchor init command followed by your project's name. This command creates a new directory with the specified name and sets up a default program and test file.

anchor init my-project

Navigate to the new project directory and open it in your code editor.

cd my-project

By default, Anchor generates a modular program structure to promote better code organization and maintainability. The program files are organized as follows:

  • /programs/my-project/src/lib.rs - Main entry point with module declarations
  • /programs/my-project/src/instructions/ - Instruction handlers
  • /programs/my-project/src/state/ - Account structures and state
  • /programs/my-project/src/constants.rs - Program constants
  • /programs/my-project/src/error.rs - Custom error definitions

The value in the declare_id! macro is the program ID, a unique identifier for your program.

By default, it is the public key of the keypair generated in /target/deploy/my_project-keypair.json.

Main entry point (lib.rs):

pub mod constants;
pub mod error;
pub mod instructions;
pub mod state;

use anchor_lang::prelude::*;

pub use constants::*;
pub use instructions::*;
pub use state::*;

declare_id!("3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg");

#[program]
pub mod my_project {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        initialize::handler(ctx)
    }
}

Instruction handler (instructions/initialize.rs):

use anchor_lang::prelude::*;

#[derive(Accounts)]
pub struct Initialize {}

pub fn handler(ctx: Context<Initialize>) -> Result<()> {
    msg!("Greetings from: {:?}", ctx.program_id);
    Ok(())
}

For simpler projects or quick prototyping, you can use the single-file template with anchor init --template single. However, the modular structure is recommended for production code as it improves code organization, readability, and maintainability.

The default Typescript test file is located at /tests/my-project.ts.

This file demonstrates how to invoke the default program's initialize instruction in Typescript.

import * as anchor from "@anchor-lang/core";
import { Program } from "@anchor-lang/core";
import { MyProject } from "../target/types/my_project";

describe("my-project", () => {
  // Configure the client to use the local cluster.
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.MyProject as Program<MyProject>;

  it("Is initialized!", async () => {
    // Add your test here.
    const tx = await program.methods.initialize().rpc();
    console.log("Your transaction signature", tx);
  });
});

If you prefer Rust for testing, initialize your project with the --test-template rust (Anchor Rust client) or --test-template mollusk (Mollusk test library) flag.

anchor init --test-template rust my-program

The Rust test file will be at /tests/src/test_initialize.rs.

use std::str::FromStr;

use anchor_client::{
    solana_sdk::{
        commitment_config::CommitmentConfig, pubkey::Pubkey, signature::read_keypair_file,
    },
    Client, Cluster,
};

#[test]
fn test_initialize() {
    let program_id = "3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg";
    let anchor_wallet = std::env::var("ANCHOR_WALLET").unwrap();
    let payer = read_keypair_file(&anchor_wallet).unwrap();

    let client = Client::new_with_options(Cluster::Localnet, &payer, CommitmentConfig::confirmed());
    let program_id = Pubkey::from_str(program_id).unwrap();
    let program = client.program(program_id).unwrap();

    let tx = program
        .request()
        .accounts(my_program::accounts::Initialize {})
        .args(my_program::instruction::Initialize {})
        .send()
        .expect("");

    println!("Your transaction signature {}", tx);
}

Build the Program

Build the program by running anchor build.

anchor build

The compiled program will be at /target/deploy/my_project.so. The content of this file is what gets stored on the Solana network (as an executable account) when you deploy your program.

Test the Program

To test the program, run anchor test.

anchor test

By default, the Anchor.toml config file specifies the localnet cluster. When developing on localnet, anchor test will automatically:

  1. Start a local Solana validator
  2. Build and deploy your program to the local cluster
  3. Run the tests in the tests folder
  4. Stop the local Solana validator

Alternatively, you can manually start a local Solana validator and run tests against it. This is useful if you want to keep the validator running while you iterate on your program. It allows you to inspect accounts and transaction logs on the Solana Explorer while developing locally.

Open a new terminal and start a local Solana validator by running the solana-test-validator command.

solana-test-validator

In a separate terminal, run the tests against the local cluster. Use the --skip-local-validator flag to skip starting the local validator since it's already running.

anchor test --skip-local-validator

Deploy to Devnet

By default, the Anchor.toml config file in an Anchor project specifies the localnet cluster.

[toolchain]

[features]
resolution = true
skip-lint = false

[programs.localnet]
my_program = "3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg"

[provider]
cluster = "Localnet"
wallet = "~/.config/solana/id.json"

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"

To deploy your program to devnet, change the cluster value to Devnet.

Note that deploying to devnet requires your wallet to have enough SOL to cover deployment cost. You can get devnet SOL using the Web Faucet.

-cluster = "Localnet"
+cluster = "Devnet"
[provider]
cluster = "Devnet"
wallet = "~/.config/solana/id.json"

Now when you run anchor deploy, your program will be deployed to the devnet cluster. The anchor test command will also use the cluster specified in the Anchor.toml file.

anchor deploy

To deploy to mainnet, simply update the Anchor.toml file to specify the mainnet cluster.

[provider]
cluster = "Mainnet"
wallet = "~/.config/solana/id.json"

Update the Program

Solana programs can be updated by redeploying the program to the same program ID.

To update a program, simply make changes to your program's code and run the anchor build command to generated an updated .so file.

anchor build

Then run the anchor deploy command to redeploy the updated program.

anchor deploy

Close the Program

To reclaim the SOL allocated to a program account, you can close your Solana program.

To close a program, use the solana program close <PROGRAM_ID> command. For example:

solana program close 3ynNB373Q3VAzKp7m4x238po36hjAGFXFJB4ybN2iTyg --bypass-warning

Note that once a program is closed, the program ID cannot be reused to deploy a new program.

Project File Structure

Below is an overview of default file structure in an Anchor workspace:

{/* cspell:disable */}

{/* cspell:enable */}

Programs Folder

The /programs directory contains your project's Anchor programs. A single workspace can contain multiple programs.

By default, programs are organized with a modular structure:

  • lib.rs - Main entry point that declares and exports modules
  • instructions/ - Directory containing instruction handler functions
  • state/ - Directory for account structures and state definitions
  • constants.rs - Program-wide constants
  • error.rs - Custom error codes

This modular organization makes it easier to navigate and maintain your code, especially as your program grows in complexity.

Tests Folder

The /tests directory contains test files for your project. A default test file is created for you when you create your project.

Target Folder

The /target directory contains build outputs. The main subfolders include:

  • /deploy: Contains the keypair and program binary for your programs.
  • /idl: Contains the JSON IDL for your programs.
  • /types: Contains the TypeScript type for the IDL.

Anchor.toml File

The Anchor.toml file configures workspace settings for your project.

.anchor Folder

Includes a program-logs file that contains transaction logs from the last run of test files.

App Folder

The /app folder is an empty folder that can be optionally used for your frontend code.