Solana: 鏈上開發入門,用 Anchor 和 Rust 構建第一個程序

大家好,如果大家對 Solana 開發充滿好奇,但又對 Rust 語言感到陌生,那么大家來對地方了。很多人在探索 Solana 這條高性能公鏈時,遇到的第一個門檻就是其原生開發語言——Rust。Rust 以其高性能和內存安全著稱,但學習曲線也相對陡峭。

幸運的是,我們有 Anchor —— 一個能讓我們“站在巨人肩膀上”的開發框架。它通過一系列宏(Macro)和約定,將復雜的 Solana 底層交互封裝起來,讓我們能更專注于業務邏輯本身。

今天,我們就以 Solana 官方文檔的第一個入門項目為例,一步步剖析代碼,讓大家不僅知道“怎么做”,更明白“為什么這么做”,順便帶大家入門 Rust 的核心語法。在這里插入圖片描述

準備工作:創建我們的 Anchor 項目

在開始之前,我們需要根據官方文檔指引,安裝好 Rust、Solana CLI 和 Anchor CLI。

安裝完成后,打開我們的終端,輸入以下命令來創建一個新的項目:

anchor init my-first-solana-app
cd my-first-solana-app

這個命令會為我們生成一個標準化的項目結構,其中最重要的文件就是 programs/my-first-solana-app/src/lib.rs。這里存放著我們鏈上程序(Program)的核心邏輯。現在,讓我們打開它,一探究竟!

代碼深潛:逐行解析 lib.rs

初次看到 lib.rs 里的代碼,我們可能會有點懵。別擔心,我們把它拆成幾個部分來看,我們會發現它像樂高積木一樣,每一塊都有清晰的功能。

這是文件的完整內容:

use anchor_lang::prelude::*;declare_id!("E3xcTbTbCYtc6XMyXv2QHBgKAeFDLqEWHCqxExpJqLsC");#[program]
pub mod my_first_solana_app {use super::*;pub fn initialize(ctx: Context<Initialize>) -> Result<()> {msg!("Greetings from: {:?}", ctx.program_id);Ok(())}
}#[derive(Accounts)]
pub struct Initialize {}
1. use anchor_lang::prelude::*; - 導入“工具箱”
  • Rust 語法點 (useprelude):
    • use 關鍵字在 Rust 中用于將外部模塊(庫)的功能引入到當前作用域。就好比在 Python 中寫 import
    • prelude(序曲)是一種常見的 Rust 編程模式。庫的作者會把最常用、最核心的組件放進一個叫 prelude 的模塊里。通過 use ...::prelude::*;,我們可以一次性導入所有必需品,省去了逐個導入的麻煩。
  • 具體作用: 這里我們導入了 anchor_lang 庫的預置模塊,它包含了構建 Anchor 程序所需的大部分基礎類型和宏,比如 Context, Result, msg! 等。
2. declare_id!("...") - 聲明程序的“身份證號”
  • Rust 語法點 (宏 !):
    • 在 Rust 中,任何以 ! 結尾的調用,都不是函數調用,而是**宏(Macro)**調用。宏可以理解為“代碼的代碼”,它能在編譯時生成或轉換代碼,功能非常強大。
  • 具體作用: declare_id! 是 Anchor 提供的一個宏。每個部署到 Solana 鏈上的程序都有一個唯一的地址,就像我們的身份證號一樣。這個宏的作用就是將我們的程序邏輯與這個鏈上地址綁定起來。當我們運行 anchor deploy 時,Anchor 會自動生成一個新的地址,并幫我們更新到這里。
3. #[program] - 神奇的“魔法帽”
  • Rust 語法點 (屬性宏 #[...]):
    • 形如 #[thing] 的語法是 Rust 的屬性宏。它可以附加到函數、模塊、結構體等代碼塊上,像一個“魔法帽”,為其附加額外的行為或進行代碼轉換。
  • 具體作用: #[program] 是 Anchor 框架的核心。它會“掃描”緊跟其后的 mod(模塊),找到所有公開的函數(比如 initialize),并將它們自動轉換為符合 Solana 規范的**指令(Instruction)**處理器。它幫我們處理了大量繁瑣的底層工作,比如指令數據的反序列化、賬戶信息的解析等。
4. pub mod my_first_solana_app { ... } - 程序的主體模塊
  • Rust 語法點 (modpub):
    • mod 關鍵字用于定義一個模塊(Module),它是 Rust 組織代碼的基本單元,類似于一個命名空間。
    • pub 關鍵字表示“公開的”(public),意味著這個模塊或函數可以被外部訪問。
  • 具體作用: 這里定義了一個名為 my_first_solana_app 的公共模塊,我們的指令邏輯都將寫在這里面。
5. pub fn initialize(ctx: Context<Initialize>) -> Result<()> - 第一個指令

這是我們程序的第一個,也是唯一一個指令。讓我們把它拆得更細:

  • pub fn initialize: 定義一個名為 initialize 的公共函數。因為 #[program] 的存在,這個函數會成為一個可以從客戶端(例如一個網頁或腳本)調用的指令。

  • ctx: Context<Initialize>: 這是理解 Anchor 的關鍵!

    • ctx 是參數名,Context<Initialize> 是它的類型。
    • Context 是 Anchor 提供的一個容器,它安全地包含了與本次調用相關的所有**賬戶(Accounts)**信息。在 Solana 中,所有數據(包括用戶信息、程序狀態等)都存儲在賬戶里。程序本身是無狀態的,它只是邏輯。
    • <Initialize> 是一個泛型參數,它告訴 Context:“嘿,請按照 Initialize 這個結構體里定義的規則來準備和校驗我需要的賬戶。”
  • -> Result<()>: 這是函數的返回值類型。

    • Rust 語法點 (Result()):
      • Result 是 Rust 用于錯誤處理的標準枚舉類型。一個 Result 要么是 Ok(value) 表示成功并攜帶一個值,要么是 Err(error) 表示失敗并攜帶一個錯誤信息。這強迫開發者必須處理可能發生的錯誤,是 Rust 安全性的重要體現。
      • () 是一個特殊的類型,叫做單元類型(Unit Type)。它表示“沒有具體的值”,類似于其他語言中的 voidnull
      • 所以 Result<()> 的意思是:如果函數成功,它不返回任何有意義的數據,只返回一個成功的信號;如果失敗,它會返回一個錯誤。
  • msg!("Hello from your first Solana program!");: 調用 msg! 宏,在鏈上日志中打印一條信息。這是我們在鏈上調試時最常用的工具,相當于 console.logprint

  • Ok(()): 表示函數成功執行。我們創建一個 Ok 變體,并用 () 作為其內容,以匹配 Result<()> 的返回類型。

6. #[derive(Accounts)]pub struct Initialize {} - 定義賬戶規則
  • Rust 語法點 (struct#[derive]):
    • struct(結構體)是 Rust 中創建自定義數據類型的方式,它是一個字段的集合。
    • #[derive(...)] 是另一個非常有用的屬性宏。它能為一個結構體自動實現某些標準的行為(在 Rust 中稱為 Traits)。
  • 具體作用:
    • pub struct Initialize {} 定義了一個名為 Initialize 的結構體。
    • #[derive(Accounts)] 是 Anchor 提供的宏,它會讀取 Initialize 結構體,并自動生成賬戶解析和安全校驗的代碼。
    • 在我們這個例子中,Initialize 是一個空結構體 {},因為它所對應的 initialize 指令不需要任何外部賬戶作為輸入。在一個更復雜的程序中,我們可能會在這里定義需要傳入的用戶賬戶、數據賬戶等。例如:
      // 這是一個虛構的例子
      #[derive(Accounts)]
      pub struct UpdateScore<'info> {#[account(mut)]pub player_stats: Account<'info, PlayerStats>, // 需要一個可修改的玩家狀態賬戶pub signer: Signer<'info>, // 需要交易發起者的簽名
      }
      
流程串講:它們是如何協同工作的?

現在,我們用一個流程圖來把所有部分串聯起來,看看當一個用戶調用我們的 initialize 指令時,背后發生了什么。
在這里插入圖片描述

這個流程清晰地展示了 Anchor 如何作為我們和底層 Solana 之間的“智能中間層”,幫我們處理了最棘手的賬戶校驗環節,讓我們可以安心地編寫核心業務邏輯。

實用建議
  1. 大膽使用 msg!:在我們學習的早期階段,不要吝嗇使用 msg!。在函數的開頭、中間、結尾打印信息,可以幫我們直觀地理解代碼的執行流程。
  2. 運行測試:在項目根目錄運行 anchor test。這個命令會編譯我們的程序,將其部署到一個本地的測試節點,并運行 tests/ 目錄下的腳本來調用我們的指令。閱讀測試腳本,可以幫我們理解如何從客戶端與程序交互。
  3. 做個小修改:嘗試修改 msg! 中的字符串,然后重新運行 anchor test,看看日志輸出是否變化。這個簡單的練習可以建立我們對“編碼->部署->測試”循環的信心。
總結

我們已經完成了對第一個 Solana 程序的深度剖析。我們來回顧一下核心要點:

  • Anchor 是我們的好朋友:它通過 #[program]#[derive(Accounts)] 等宏,極大地簡化了開發。
  • Rust 沒那么可怕:我們接觸了它的模塊(mod)、函數(fn)、結構體(struct)、錯誤處理(Result)以及強大的宏系統。這些特性共同構建了一個安全而高效的編程環境。
  • 一切皆賬戶:Solana 的核心是賬戶模型,Anchor 的 Context#[derive(Accounts)] 為我們提供了安全、便捷的方式來操作賬戶。

從這個簡單的 “Hello World” 出發,我們已經掌握了理解更復雜 Solana 程序的基礎。繼續探索,嘗試為我們的程序添加狀態,或者定義需要更多賬戶的指令。編程之路,始于足下。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/91657.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/91657.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/91657.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

node.js之Koa框架

Koa框架介紹Koa 是一個新的 web 框架&#xff0c;由 Express 原班人馬打造&#xff0c;致力于成為一個更小、更富有表現力、更健壯的 Web 框架。Koa 解決了 Express 存在的一些問題&#xff0c;例如&#xff1a;中間件嵌套回調&#xff08;callback hell&#xff09;錯誤處理不…

C/C++離線環境安裝(VSCode + MinGW)

因為工作需要部署離線C環境&#xff0c;網上有許多大佬分享了不錯的教程&#xff0c;總結一篇完整教程自用&#xff0c;使用VSCode MinGW感謝一、安裝準備二、軟件安裝1.安裝MinGW2.安裝VSCode及插件三、測試環境1.創建工程文件夾2.創建cpp文件總結感謝 本教程參考了以下教程…

如何創建一個飛書應用獲取自己的飛書AppID和AppSecret?

這篇文章是接下來要開發「監控 X&#xff08;原Twitter&#xff09;博主賬號最新推文」 自動化工作流的先導文章&#xff0c;由于內容相對獨立&#xff0c;也可用于飛書應用的其他場景&#xff0c;故單獨發出來&#xff0c;方便查閱。 監控X平臺指定博主最新發文&#xff0c;需…

Prompt工程記錄

Prompt基本建議&#xff1a;1.在查詢中包含詳細信息以獲得更相關的答案總結會議筆記:先將會議筆記總結為一段&#xff0c;然后寫一份演講者的打分表&#xff0c;列出他們的每個要點&#xff1b;最后列出發言者建議的下一步行動或者行動項目&#xff08;如果有的話&#xff09;2…

CTE公用表表達式的可讀性與性能優化

一、可讀性優化CTE通過WITH子句定義臨時命名結果集&#xff0c;將復雜查詢分解為邏輯獨立的模塊&#xff0c;顯著提升代碼清晰度與可維護性?&#xff1a;?解構嵌套查詢?&#xff1a;將多層嵌套的子查詢扁平化&#xff0c;例如傳統嵌套統計訂單的查詢可重構為分步CTE&#xf…

8.1.2 TiDB存儲引擎的原理

TiDB 簡介 TiDB 是 PingCAP 公司自主設計、研發的開源分布式關系型數據 庫&#xff0c;是一款同時支持在線事務處理與在線分析處理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布 式數據庫產品&#xff0c;具備水平擴容或者縮容、金融級高可用、實時 …

PTE之路--01

空格繞過:/**/ URL編碼偽協議:pagezip://xxx/xx/x/x/xxx.jpg%23解壓后的名字pagephar://xxx/xx/x/x/xxx.jpg/解壓后的名字pageddata://ata://text/plain,<?php eval($_POST[x]) ;?>pagedata://text/plain,<?php eval($_POST[x]) ;?>127.0.0.1 | grep . ../key…

企業級日志分析系統ELK

1.什么是 Elastic Stack 如果系統和應用出現異常和問題,相關的開發和運維人員想要排查原因,就要先登錄到應用運行所相應的主機,找到上面的相關日志文件再進行查找和分析,所以非常不方便,此外還會涉及到權限和安全問題,而ELK 的出現就很好的解決這一問題。 ELK 是由一家 …

ai項目多智能體

手把手教你構建一個 本地化的&#xff0c;免費的&#xff0c;企業級的&#xff0c;AI大模型知識庫問答系統 - 網旭哈瑞.AI 體驗 AutoGen Studio - 微軟推出的友好多智能體協作框架_autogenstudio-CSDN博客 AutoGen Studio: Interactively Explore Multi-Agent Workflows | Au…

【HTML】淺談 script 標簽的 defer 和 async

The async and defer attributes are boolean attributes that indicate how the script should be evaluated. There are several possible modes that can be selected using these attributes, depending on the script’s type. async 和 defer 屬性是布爾屬性&#xff0c;…

Kafka Streams 并行處理機制深度解析:任務(Task)與流線程(Stream Threads)的協同設計

在構建實時流處理應用時&#xff0c;如何充分利用計算資源同時保證處理效率是一個關鍵問題。Kafka Streams 通過其獨特的任務(Task)和流線程(Stream Threads)并行模型&#xff0c;為開發者提供了既簡單又強大的并行處理能力。本文將深入解析 Kafka Streams 中任務與線程的協同工…

使用 Docker 部署 Label Studio 時本地文件無法顯示的排查與解決

目錄 使用 Docker 部署 Label Studio 時本地文件無法顯示的排查與解決 1. 背景 2. 問題現象 3. 排查步驟 3.1 確認文件是否存在 3.2 檢查環境變量配置 4. 解決方案 方法一&#xff1a;修改 Sync Storage 路徑&#xff08;相對路徑&#xff09; 方法二&#xff1a;修改…

ElasticJob怎么使用?

我們使用ElasticJob需要以下步驟&#xff1a; 1. 添加依賴 2. 配置任務&#xff08;可以使用Spring命名空間配置或Java配置&#xff09; 3. 實現任務邏輯&#xff08;實現SimpleJob、DataflowJob等接口&#xff09; 4. 啟動任務 下面是一個詳細的示例&#xff0c;包括Spring Bo…

TCP協議的特點和首部格式

文章目錄TCP協議是什么&#xff1f;TCP協議的主要特點1. 面向連接2. 可靠傳輸3. 流量控制4. 擁塞控制TCP首部格式源端口和目標端口&#xff08;各16位&#xff09;序列號&#xff08;32位&#xff09;確認號&#xff08;32位&#xff09;數據偏移&#xff08;4位&#xff09;保…

IO流-文件的常用方法

1.關于java.io.File類- File類只能表示計算機中的文件或目錄而不能獲取或操作文件- 通過File類獲得到文件的基本信息&#xff0c;如文件名、大小等&#xff0c;但不能獲取文件內容- java中表示文件路徑分隔符使用"/"或"\\"- File類中的構造方法- File(&quo…

AUTOSAR進階圖解==>AUTOSAR_SRS_E2E

AUTOSAR E2E通信保護解析 AUTOSAR End-to-End通信保護機制詳解與應用目錄 概述 1.1. AUTOSAR E2E通信保護的作用 1.2. E2E通信保護的應用場景AUTOSAR E2E架構 2.1. E2E組件層次結構 2.2. E2E庫和E2E轉換器E2E監控狀態機 3.1. 狀態定義與轉換 3.2. 狀態機實現E2E保護數據交換流…

鏡像快速部署ollama+python+ai

算力租賃入口&#xff1a;https://www.jygpu.com為大家提供以上鏡像快速部署方式&#xff0c;節約大家環境部署時間一鍵部署的便捷性傳統自建GPU服務器需要經歷復雜的硬件采購、驅動安裝、環境配置等繁瑣步驟&#xff0c;而現代??GPU租賃價格對比??顯示&#xff0c;容器化平…

使用Gemini API開發領域智能聊天機器人的思路

以下是使用 Gemini API 開發軟件自動化測試專家領域專屬智能聊天機器人的詳細思路及具體實現過程&#xff1a; 階段一&#xff1a;基礎準備與規劃 (Foundation & Planning) 這個階段的目標是明確方向、準備好所有必要的工具和憑證。 步驟 1&#xff1a;明確聊天機器人的目…

第13屆藍橋杯Python青少組_省賽_中/高級組_2022年4月17日真題

更多內容請查看網站&#xff1a;【試卷中心 -----> 藍橋杯----> Python----> 省賽】 網站鏈接 青少年軟件編程歷年真題模擬題實時更新 第13屆藍橋杯Python青少組_省賽_中/高級組_2022年4月17日真題 一、選擇題 第 1 題 下列二進制數中最大的是&#xff08; &a…

sqli-labs:Less-17關卡詳細解析

1. 思路&#x1f680; 本關的SQL語句為&#xff1a; $sql"SELECT username, password FROM users WHERE username $uname LIMIT 0,1"; $update"UPDATE users SET password $passwd WHERE username$row1";注入類型&#xff1a;字符串型&#xff08;單引號…