动态

详情 返回 返回

Web3實戰:使用Anchor與Rust開發和調用Solana智能合約 - 动态 详情

Web3實戰:使用Anchor與Rust開發和調用Solana智能合約

Web3時代正在重塑數字世界,Solana以其超高吞吐量和低交易成本成為區塊鏈開發的明星平台。想快速上手Web3開發?本文通過一個簡單的計數器智能合約,帶你一步步掌握使用Anchor框架和Rust語言在Solana上開發、部署智能合約,以及編寫Rust客户端與合約交互的完整流程。無論你是區塊鏈新手還是尋求實戰經驗的開發者,這篇教程都將為你打開Web3開發的大門!

本文是一篇面向Web3開發者的實戰教程,基於Solana區塊鏈和Anchor框架,完整展示如何從零開始構建和調用智能合約。內容分為兩部分:一、Anchor開發Solana智能合約,涵蓋項目初始化、Rust合約編寫、編譯、啓動本地節點和部署合約的全流程;二、Rust客户端調用合約,通過anchor-client庫實現初始化和遞增計數器功能。教程提供詳細代碼、運行結果及參考資源,適合希望快速上手Solana開發的初學者和進階開發者。

Anchor開發Solana智能合約全流程

創建並初始化項目

anchor init counter
yarn install v1.22.22
info No lockfile found.
[1/4] 🔍  Resolving packages...
warning mocha > glob@7.2.0: Glob versions prior to v9 are no longer supported
warning mocha > glob > inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
✨  Done in 17.91s.
Failed to install node modules
Initialized empty Git repository in /Users/qiaopengjun/Code/Solana/solana-sandbox/counter/.git/
counter initialized

若遇到安裝失敗,可嘗試更新Node.js版本或使用npm install替代。

切換到項目目錄並用 cursor 打開

cd counter
cc

查看項目目錄

counter on  main [?] via ⬢ v23.11.0 via 🦀 1.87.0 
➜ tree . -L 6 -I "target|test-ledger|.vscode|node_modules"
.
├── Anchor.toml
├── app
│   └── counter-rs
│       ├── Cargo.lock
│       ├── Cargo.toml
│       ├── idls
│       │   └── counter.json
│       └── src
│           └── main.rs
├── Cargo.lock
├── Cargo.toml
├── migrations
│   └── deploy.ts
├── package.json
├── programs
│   └── counter
│       ├── Cargo.toml
│       ├── src
│       │   └── lib.rs
│       └── Xargo.toml
├── tests
│   └── counter.ts
├── tsconfig.json
└── yarn.lock

10 directories, 15 files

lib.rs 文件

#![allow(unexpected_cfgs)]

use anchor_lang::prelude::*;

declare_id!("8KYmW4jDPnzXRCFR2c5b1VLRdFBsaEJk1RjUgqn7F35V");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let counter = &ctx.accounts.counter;
        msg!("Counter account created! Current count: {}", counter.count);
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        msg!("Previous counter: {}", counter.count);

        counter.count += 1;
        msg!("Counter incremented! Current count: {}", counter.count);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(mut)]
    pub payer: Signer<'info>,

    #[account(
        init,
        payer = payer,
        space = 8 + 8
    )]
    pub counter: Account<'info, Counter>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}

#[account]
pub struct Counter {
    pub count: u64,
}

此代碼定義了計數器合約的initialize和increment指令,分別用於創建計數器賬户和遞增計數。

編譯

counter on  main [?] via ⬢ v23.11.0 via 🦀 1.87.0 
➜ anchor build    
   Compiling counter v0.1.0 (/Users/qiaopengjun/Code/Solana/solana-sandbox/counter/programs/counter)
    Finished `release` profile [optimized] target(s) in 1.45s
   Compiling counter v0.1.0 (/Users/qiaopengjun/Code/Solana/solana-sandbox/counter/programs/counter)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 1.46s
     Running unittests src/lib.rs (/Users/qiaopengjun/Code/Solana/solana-sandbox/counter/target/debug/deps/counter-c2859c9ce41300ce)

啓動本地節點

counter on  main [?] via ⬢ v23.11.0 via 🦀 1.87.0 
➜ anchor localnet 
    Finished `release` profile [optimized] target(s) in 0.25s
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.42s
     Running unittests src/lib.rs (/Users/qiaopengjun/Code/Solana/solana-sandbox/counter/target/debug/deps/counter-c2859c9ce41300ce)
Ledger location: .anchor/test-ledger
Log: .anchor/test-ledger/validator.log
⠁ Initializing...                                                                                                Waiting for fees to stabilize 1...
Identity: HtjDDGXEmbtGmnTZS3ZKRQhRyiZuU3ca8qJGP8LFwqF1
Genesis Hash: FzJe5U98Kht3h7Vwfy4f4qnU2uMZkrwMZq8RakWmzd8t
Version: 2.1.21
Shred Version: 37242
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899
WebSocket PubSub URL: ws://127.0.0.1:8900
⠒ 00:04:04 | Processed Slot: 512 | Confirmed Slot: 512 | Finalized Slot: 481 | Full Snapshot Slot: 400 | Incrementa

部署合約

counter on  main [?] via ⬢ v23.11.0 via 🦀 1.87.0 took 4.0s 
➜ anchor deploy
Deploying cluster: http://127.0.0.1:8899
Upgrade authority: /Users/qiaopengjun/.config/solana/id.json
Deploying program "counter"...
Program path: /Users/qiaopengjun/Code/Solana/solana-sandbox/counter/target/deploy/counter.so...
Program Id: 8KYmW4jDPnzXRCFR2c5b1VLRdFBsaEJk1RjUgqn7F35V

Signature: 4dT2ohhVS9Jv14juxV44F112Z5Zh2fEQSx9fzakn6ADomo2TP4qFRSJeFv9eAYZDTUbWj2Uwj39cApDKzKR3Lv7V

Deploy success

Rust客户端調用合約實戰

複製 IDL 到客户端目錄

counter on  main [?] via ⬢ v23.11.0 via 🦀 1.87.0 took 4.6s 
➜ cp -a target/idl/counter.json app/counter-rs/idls

counter-rs/src/main.rs 文件

use anchor_client::{
    Client, Cluster,
    solana_client::rpc_client::RpcClient,
    solana_sdk::{
        commitment_config::CommitmentConfig, native_token::LAMPORTS_PER_SOL, signature::Keypair,
        signer::Signer, system_program,
    },
};
use anchor_lang::prelude::*;
use std::rc::Rc;

declare_program!(counter);
use counter::{accounts::Counter, client::accounts, client::args};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let connection = RpcClient::new_with_commitment(
        "http://127.0.0.1:8899", // Local validator URL
        CommitmentConfig::confirmed(),
    );

    // Generate Keypairs and request airdrop
    let payer = Keypair::new();
    let counter = Keypair::new();
    let counter_pubkey: Pubkey = counter.pubkey(); // 保存公鑰

    println!("Generated Keypairs:");
    println!("   Payer: {}", payer.pubkey());
    println!("   Counter: {}", counter_pubkey);

    println!("\nRequesting 1 SOL airdrop to payer");
    let airdrop_signature = connection.request_airdrop(&payer.pubkey(), LAMPORTS_PER_SOL)?;

    // Wait for airdrop confirmation
    while !connection.confirm_transaction(&airdrop_signature)? {
        std::thread::sleep(std::time::Duration::from_millis(100));
    }
    println!("   Airdrop confirmed!");

    // Create program client
    let provider = Client::new_with_options(
        Cluster::Localnet,
        Rc::new(payer),
        CommitmentConfig::confirmed(),
    );
    let program = provider.program(counter::ID)?;

    // Build and send instructions
    println!("\nSend transaction with initialize and increment instructions");
    let initialize_ix = program
        .request()
        .accounts(accounts::Initialize {
            counter: counter.pubkey(),
            payer: program.payer(),
            system_program: system_program::ID,
        })
        .args(args::Initialize)
        .instructions()?
        .remove(0);

    let increment_ix = program
        .request()
        .accounts(accounts::Increment {
            counter: counter.pubkey(),
        })
        .args(args::Increment)
        .instructions()?
        .remove(0);

    let signature = program
        .request()
        .instruction(initialize_ix)
        .instruction(increment_ix)
        .signer(counter)
        .send()
        .await?;
    println!("   Transaction confirmed: {}", signature);

    println!("\nFetch counter account data");
    let counter_account: Counter = program.account::<Counter>(counter_pubkey).await?;
    println!("   Counter value: {}", counter_account.count);
    Ok(())
}

此客户端代碼通過anchor-client庫與合約交互,執行初始化和遞增操作。

查看客户端目錄

counter/app/counter-rs on  main [?] is 📦 0.1.0 via ⬢ v23.11.0 via 🦀 1.87.0 
➜ tree . -L 6 -I "target|test-ledger|.vscode|node_modules"
.
├── Cargo.lock
├── Cargo.toml
├── idls
│   └── counter.json
└── src
    └── main.rs

3 directories, 4 files

編譯構建

counter/app/counter-rs on  main [?] is 📦 0.1.0 via ⬢ v23.11.0 via 🦀 1.87.0 
➜ cargo build
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.76s

運行

counter/app/counter-rs on  main [?] is 📦 0.1.0 via ⬢ v23.11.0 via 🦀 1.87.0 
➜ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.71s
     Running `target/debug/counter-rs`
Generated Keypairs:
   Payer: 2yGfFA4PePJrxvzsyRsdJowTZU6wQicJXGytEZLK7gfU
   Counter: Cm1Z47iBmTw9vvd6as4mHx8wjw2Bdhxc3DLC1ySsmxdM

Requesting 1 SOL airdrop to payer
   Airdrop confirmed!

Send transaction with initialize and increment instructions
   Transaction confirmed: nixZo67eWi8KqQ2i9gJie44Ed9hpNNpLMrHujDg7vNHP9NTnJPTHQDZCMKhww9Xym8gW3JoVjxiuLPddBFmxDHV

Fetch counter account data
   Counter value: 1
   
counter/app/counter-rs on  main [?] is 📦 0.1.0 via ⬢ v23.11.0 via 🦀 1.87.0 took 2.3s 
➜ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.63s
     Running `target/debug/counter-rs`
Generated Keypairs:
   Payer: 7H8VyPGELkE8A3Z4dPbRNHWmT17wXoNFg392qcKFnkXL
   Counter: FGUy5G7mH7PGr6RNrzdzVd249DV7pSTreHa8G8YkQGQN

Requesting 1 SOL airdrop to payer
   Airdrop confirmed!

Send transaction with initialize and increment instructions
   Transaction confirmed: W6ECp3DF3PYm6rMxn69LKPe86vNRvKwaB1iKBNJoLsgopkgkKxuDhfFyJT2gKtpPVYykf3yg6jT49bWw8UFLCTg

Fetch counter account data
   Counter value: 1

總結

通過本教程,你已掌握使用Anchor框架在Solana區塊鏈上開發和部署計數器智能合約的核心技能,並學會如何用Rust客户端與合約交互。從項目初始化到合約調用,這篇實戰指南展示了Solana生態的高效與Rust語言的強大。Web3的未來充滿無限可能,立即動手實踐,構建你的第一個去中心化應用(DApp)!

想深入探索Solana開發?掃描下方二維碼,關注我們獲取更多Web3實戰教程!

在評論區分享你的Solana開發經驗,或留言你的問題,我們一起探討!

參考

  • https://www.anchor-lang.com/docs/clients/rust
  • https://www.rust-lang.org/zh-CN
  • https://course.rs/about-book.html
  • https://lab.cs.tsinghua.edu.cn/rust/
  • https://rustwasm.github.io/book/
  • https://solana.com/zh/docs
  • https://solanacookbook.com/zh/
  • https://www.solanazh.com/

Add a new 评论

Some HTML is okay.