最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

當(dāng)前位置:主頁 > 區(qū)塊鏈 > 區(qū)塊鏈技術(shù) > solana開發(fā)教程

Solana開發(fā)學(xué)習(xí)筆記(一)——從Hello World出發(fā)

2024-04-30 14:42:33 | 來源: | 作者:佚名
本章對Solana區(qū)塊鏈的基本概念進(jìn)行了簡要介紹,并介紹了開發(fā)Solana鏈上程序必須安裝和配置的編程環(huán)境,通過對Hello World這個官方演示項目源碼的解讀,了解如何使用Rust開發(fā)鏈上程序,并使用Solana CLI來構(gòu)建與部署,以及使用Solana JavaScript SDK與鏈上程序進(jìn)行交互

筆者注:因近期筆者工作需要,開始接觸 Solana 鏈上程序開發(fā)。本系列文章是筆者的學(xué)習(xí)筆記,既是為了備忘,也是希望得到 Solana 開發(fā)者的指點與交流。本系列文章將默認(rèn)讀者已經(jīng)掌握 Rust 的基礎(chǔ)語法,故不涉及對 Rust 語法細(xì)節(jié)的解釋。如果讀者對 Rust 基礎(chǔ)語法還不熟練的話,本文下方推薦的 Rust 入門書籍《Rust 編程入門、實戰(zhàn)與進(jìn)階》學(xué)習(xí)。

1.1 Solana 簡介

Solana 是一個高性能、無許可的底層公鏈,專注于在不犧牲去中心化或安全性的前提下提供可擴(kuò)展性。Solana 主網(wǎng)于 2020 年一季度上線,目前主網(wǎng)的全球節(jié)點超過 800 個,TPS 最高可達(dá) 6.5 萬,出塊時間約 400 毫秒。

Solana 的共識算法采用 PoH(歷史證明),其核心是一個去中心化時鐘,該時鐘旨在解決缺乏單個可信賴時間源在分布式網(wǎng)絡(luò)中的時間問題。PoH 免除了在節(jié)點網(wǎng)絡(luò)中廣播時間戳的需求,從而提高整個網(wǎng)絡(luò)的效率。

1.1.1 鏈上程序

Solana 的智能合約叫做鏈上程序(On-chain Program),Solana 官方提供了 Rust 和 C 的 SDK 來支持開發(fā)鏈上程序。鏈上程序的開發(fā)工作流如圖 1-1 所示,開發(fā)者可以使用工具將程序編譯成 Berkley Packet Filter (BPF) 字節(jié)碼(文件以 .so 為擴(kuò)展名),再部署到 Solana 鏈上,通過 Sealevel 并行智能合約運(yùn)行時去執(zhí)行智能合約的邏輯。此外,基于 Solana JSON RPC API,官方提供了諸多 SDK 用于客戶端與 Solana 鏈上數(shù)據(jù)交互。

圖 1-1 鏈上程序開發(fā)工作流

1.1.2 賬戶模型

與以太坊類似,Solana 也是基于賬戶模型的區(qū)塊鏈。通過將任意狀態(tài)存儲于鏈上賬戶并同步復(fù)制給集群中的所有節(jié)點,可以創(chuàng)建復(fù)雜而強(qiáng)大的去中心化應(yīng)用程序。

Solana 提供了一套不同于以太坊的賬戶模型,賬戶定義的字段如表 1-1 所示。Solana 的賬戶可以分為可執(zhí)行賬戶和不可執(zhí)行賬戶。

  • 可執(zhí)行賬戶:存儲不可變的數(shù)據(jù),主要用于存儲程序的 BPF 字節(jié)碼。
  • 不可執(zhí)行賬戶:存儲可變的數(shù)據(jù),主要用于存儲程序的狀態(tài)。

表 1-1 賬戶定義字段

字段描述
lamports賬戶余額
owner賬戶所有者
executable是否為可執(zhí)行賬戶
data賬戶存儲的數(shù)據(jù)
rent_epochSolana鏈上程序的部署是按其賬戶大小進(jìn)行定期收費(fèi)的,如果賬戶無法支付租金,系統(tǒng)將清除該賬號

我們知道以太坊上每個智能合約的代碼和狀態(tài)都存儲在同一個賬戶中,而 Solana 鏈上程序是只讀或無狀態(tài)的,即程序的賬戶(可執(zhí)行賬戶)只存儲 BPF 字節(jié)碼,不存儲任何狀態(tài),程序會把狀態(tài)存儲在其他獨立的賬戶(不可執(zhí)行賬戶)中。為了區(qū)分某個賬戶是用作哪個程序的狀態(tài)存儲,每個賬戶都指定了一個程序作為其所有者。程序可以讀取其不作為所有者的賬戶中的狀態(tài),但只有作為所有者的程序才能修改賬戶中的狀態(tài),任何其他程序所做的修改都會被還原并導(dǎo)致交易失敗。

更多關(guān)于賬戶模型的資料可以參見官方文檔:https://solana.wiki/zh-cn/docs/account-model/

1.2 搭建編程環(huán)境

在開始 Solana 鏈上程序開發(fā)之前,需要先安裝和配置相關(guān)的編程環(huán)境。首先請正確安裝 Node、NPM 和 Rust 的最新穩(wěn)定版本,下面來安裝 Solana CLI 并配置相關(guān)環(huán)境。

1.2.1 安裝 Solana CLI

Solana CLI 是與 Solana 集群進(jìn)行交互的命令行管理工具,包含節(jié)點程序 solana-validator、密鑰對生成工具 solana-keygen,以及合約開發(fā)工具 cargo-build-bpf、cargo-test-bpf 等。

在終端運(yùn)行以下命令,可完成 Solana CLI 最新穩(wěn)定版的下載與安裝。

sh -c "$(curl -sSfL https://release.solana.com/stable/install)"

如果安裝成功,會出現(xiàn)以下內(nèi)容。

downloading stable installer
  ? stable commit e9bef425 initialized
Adding export PATH="~/.local/share/solana/install/active_release/bin:$PATH" to ~/.profile
Adding export PATH="~/.local/share/solana/install/active_release/bin:$PATH" to ~/.bash_profile
Close and reopen your terminal to apply the PATH changes or run the following in your existing shell:
  export PATH="~/.local/share/solana/install/active_release/bin:$PATH"

Solana CLI 的所有命令行工具都安裝在 ~/.local/share/solana/install/active_release/bin 中,并會自動將該路徑加入 ~/.profile 和 ~/.bash_profile 文件的 PATH 環(huán)境變量。

運(yùn)行以下命令,檢查 PATH 環(huán)境變量是否已正確設(shè)置。

solana --version
// solana-cli 1.7.18 (src:e9bef425; feat:140464022)

如果能顯示 solana-cli 的版本號、版本哈希等信息,代表環(huán)境變量設(shè)置成功。如果未看到這些信息,請檢查相關(guān)文件中 PATH 環(huán)境變量設(shè)置的路徑是否正確。

如果已安裝過 Solana CLI,想升級到最新版本,可在終端運(yùn)行以下命令。

solana-install update

1.2.2 配置 Solana CLI

1. 連接到集群

Solana 的集群有本地集群(localhost)和公開集群。根據(jù)不同的用途,公開集群又分為開發(fā)者網(wǎng)絡(luò)(devnet)、測試網(wǎng)(testnet)和主網(wǎng)(mainnet-beta)。

  • devnet 是適用于開發(fā)者的集群,開發(fā)者可獲得 SOL token 的空投,但這個 SOL token 不具有真實價值,僅限測試使用。devnet 的 RPC 鏈接是 https://api.devnet.solana.com 。
  • testnet 是用于測試最新功能的集群,如網(wǎng)絡(luò)性能、穩(wěn)定性和驗證程序行為等。同樣可獲得 SOL token 的空投,但也僅限測試使用。testnet 的 RPC 鏈接是 https://api.testnet.solana.com 。
  • mainnet-beta 是主網(wǎng)集群,在 Mainnet Beta 上發(fā)行的 SOL token 具有真實價值。mainnet-beta 的 RPC 鏈接是 https://api.mainnet-beta.solana.com 。

運(yùn)行以下命令,根據(jù)實際需要來選擇集群。

// 選擇localhost集群
solana config set --url localhost
// 選擇devnet集群
solana config set --url devnet

2. 創(chuàng)建賬戶

如果是第一次使用 Solana CLI,需要先創(chuàng)建一個賬戶。運(yùn)行以下命令,根據(jù)操作提示可以設(shè)置一個 BIP39 規(guī)范的密碼,此密碼用來增強(qiáng)助記詞的安全性,當(dāng)然也可以為空。生成新的賬戶后,密鑰對會被自動寫入 ~/.config/solana/id.json 文件中。需要注意的是,這種存儲密鑰對的方式是不安全的,僅限開發(fā)測試使用。

solana-keygen new

要查看當(dāng)前這個賬戶的公鑰,運(yùn)行以下命令。

solana-keygen pubkey

當(dāng)前如果是在 devnet 集群,該賬戶的余額為 0 SOL,可以運(yùn)行以下命令查詢余額。

solana balance

在 devnet 上申請 SOL 空投,運(yùn)行以下命令后再次查詢當(dāng)前賬戶的余額,會發(fā)現(xiàn)余額為 2 SOL。

solana airdrop 2

1.3 第一個 Solana 項目——Hello World

Hello World 是一個官方演示項目,展示了如何使用 Rust 和 C 開發(fā)鏈上程序,并使用 Solana CLI 來構(gòu)建與部署,以及使用 Solana JavaScript SDK 與鏈上程序進(jìn)行交互。

1.3.1 Hello World 源碼解讀

example-helloworld 項目的目錄結(jié)構(gòu)如下所示,其中 program-rust 目錄下是 Rust 開發(fā)的程序源代碼,client 目錄下是客戶端的源代碼。

example-helloworld
|
+-- src
|  |
|  +-- client
|  |  |
|  |  +-- hello_world.ts
|  |  |
|  |  +-- main.ts
|  |  |
|  |  +-- utils.ts
|  |
|  +-- program-rust
|  |  |
|  |  +-- src
|  |  |  |
|  |  |  +-- lib.rs
|  |  |
|  |  +-- tests
|  |  |  |
|  |  |  +-- lib.rs
|  |  |
|  |  +-- Cargo.toml
|  |  |
|  |  +-- Xargo.toml
|
+-- .gitignore
|
+-- package.json
|
+-- tsconfig.json

1. 鏈上程序源碼解讀

program-rust/src/lib.rs 是鏈上程序的核心代碼,如代碼清單 1-1 所示,實現(xiàn)了將程序被調(diào)用次數(shù)存儲在鏈上賬戶中。

第 1 行代碼將 borsh::BorshDeserialize 和 borsh::BorshSerialize 引入本地作用域,用于序列化和反序列化數(shù)據(jù)。第 2~9 行代碼將 Solana Rust SDK 的模塊引入本地作用域,使用 Rust 編寫程序都需要這個 SDK。

第 13~16 行代碼定義了 GreetingAccount 結(jié)構(gòu)體作為存儲在賬戶中的狀態(tài)類型,里面有一個 u32 類型的字段 counter,用于記錄程序被有效調(diào)用的次數(shù)。

第 19 行代碼 entrypoint 聲明了 process_instruction 函數(shù)是程序入口,每個程序都有一個唯一的入口。第 22~26 行代碼是 process_instruction 函數(shù)簽名,它要接收 3 個參數(shù):

  • program_id:鏈上程序的部署地址,在這里也就是 helloworld 程序賬戶的公鑰。
  • accounts:與程序交互的賬戶列表,當(dāng)前程序會使用賬戶列表中的賬戶來存儲狀態(tài)或修改賬戶中的數(shù)據(jù)。如果當(dāng)前程序不是某個賬戶的所有者,那就無法使用該賬戶存儲狀態(tài)或修改數(shù)據(jù),當(dāng)前交易會執(zhí)行失敗。
  • instruction_data:指令數(shù)據(jù),比如要轉(zhuǎn)賬的代幣數(shù)量、轉(zhuǎn)賬地址等。

process_instruction 函數(shù)的返回值類型是 ProgramResult,ProgramResult 類型的定義如下所示。

pub type ProgramResult = Result<(), ProgramError>;

當(dāng)程序的邏輯執(zhí)行成功時返回 Ok(()),否則將 ProgramError 錯誤返回。ProgramError 是自定義錯誤的枚舉類型,其中包含程序可能失敗的各種原因。

第 27 行代碼使用 msg! 宏將字符串輸出到日志中,方便觀察業(yè)務(wù)的執(zhí)行邏輯和調(diào)試信息。第 30 行代碼通過 iter 方法將賬戶列表轉(zhuǎn)換為迭代器,以安全的方式獲取賬戶地址。第 33 行代碼使用了 ? 操作符,如果迭代器中有賬戶地址,會將賬戶地址與變量 account 綁定。如果迭代器中沒有賬戶地址,? 操作符會讓程序執(zhí)行失敗。

第 36~39 行代碼判斷存儲狀態(tài)的賬戶所有者是否是當(dāng)前程序。只有賬戶所有者才能修改數(shù)據(jù),否則輸出日志并返回。

第 42~44 行代碼先對賬戶中的數(shù)據(jù)進(jìn)行反序列化操作,再將 counter 加一,最后將其序列化后存儲到賬戶中。

代碼清單 1-1 helloworld 鏈上程序

use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
};

/// Define the type of state stored in accounts
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    /// number of greetings
    pub counter: u32,
}

// Declare and export the program's entrypoint
entrypoint!(process_instruction);

// 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(())
}

2. 客戶端程序源碼解讀

要想測試鏈上程序,我們必須通過 Solana JSON RPC API 去和鏈上程序進(jìn)行交互。example-helloworld 項目提供的客戶端用 Typescript 編寫,使用了 web3.js 庫這個 Solana JavaScript SDK。

在 client 目錄下,客戶端執(zhí)行的入口是 main.ts 文件,它按特定的順序執(zhí)行任務(wù),每個任務(wù)的業(yè)務(wù)邏輯代碼在 hello_world.ts 文件。

首先,客戶端調(diào)用 establishConnection 函數(shù)與集群建立連接。

export async function establishConnection(): Promise<void> {
  const rpcUrl = await getRpcUrl();
  connection = new Connection(rpcUrl, 'confirmed');
  const version = await connection.getVersion();
  console.log('Connection to cluster established:', rpcUrl, version);
}

接著,客戶端調(diào)用 establishPayer 函數(shù)來確保有一個有支付能力的賬戶。

export async function establishPayer(): Promise<void> {
  let fees = 0;
  if (!payer) {
    const {feeCalculator} = await connection.getRecentBlockhash();

    // Calculate the cost to fund the greeter account
    fees += await connection.getMinimumBalanceForRentExemption(GREETING_SIZE);

    // Calculate the cost of sending transactions
    fees += feeCalculator.lamportsPerSignature * 100; // wag

    try {
      // Get payer from cli config
      payer = await getPayer();
    } catch (err) {
      // Fund a new payer via airdrop
      payer = await newAccountWithLamports(connection, fees);
    }
  }

  const lamports = await connection.getBalance(payer.publicKey);
  if (lamports < fees) {
    // This should only happen when using cli config keypair
    const sig = await connection.requestAirdrop(
      payer.publicKey,
      fees - lamports,
    );
    await connection.confirmTransaction(sig);
  }

  console.log(
    'Using account',
    payer.publicKey.toBase58(),
    'containing',
    lamports / LAMPORTS_PER_SOL,
    'SOL to pay for fees',
  );
}

然后,客戶端調(diào)用 checkProgram 函數(shù)從 src/program-rust/target/deploy/helloworld-keypair.json 中加載已部署程序的密鑰對(此操作前需先構(gòu)建鏈上程序,詳見 1.3.2 節(jié)),并使用密鑰對的公鑰來獲取程序賬戶。如果程序不存在,客戶端會報錯并停止執(zhí)行。如果程序存在,將創(chuàng)建一個新賬戶來存儲狀態(tài),并以該程序作為新賬戶所有者。這里新賬戶存儲的狀態(tài),就是程序被調(diào)用的次數(shù)。

export async function checkProgram(): Promise<void> {
  // Read program id from keypair file
  try {
    const programKeypair = await createKeypairFromFile(PROGRAM_KEYPAIR_PATH);
    programId = programKeypair.publicKey;
  } catch (err) {
    const errMsg = (err as Error).message;
    throw new Error(
      `Failed to read program keypair at '${PROGRAM_KEYPAIR_PATH}' due to error: ${errMsg}.`,
    );
  }

  // Check if the program has been deployed
  const programInfo = await connection.getAccountInfo(programId);
  if (programInfo === null) {
    if (fs.existsSync(PROGRAM_SO_PATH)) {
      throw new Error(
        'Program needs to be deployed with `solana program deploy dist/program/helloworld.so`',
      );
    } else {
      throw new Error('Program needs to be built and deployed');
    }
  } else if (!programInfo.executable) {
    throw new Error(`Program is not executable`);
  }
  console.log(`Using program ${programId.toBase58()}`);

  // Derive the address (public key) of a greeting account from the program so that it's easy to find later.
  const GREETING_SEED = 'hello';
  greetedPubkey = await PublicKey.createWithSeed(
    payer.publicKey,
    GREETING_SEED,
    programId,
  );

  // Check if the greeting account has already been created
  const greetedAccount = await connection.getAccountInfo(greetedPubkey);
  if (greetedAccount === null) {
    console.log(
      'Creating account',
      greetedPubkey.toBase58(),
      'to say hello to',
    );
    const lamports = await connection.getMinimumBalanceForRentExemption(
      GREETING_SIZE,
    );

    const transaction = new Transaction().add(
      SystemProgram.createAccountWithSeed({
        fromPubkey: payer.publicKey,
        basePubkey: payer.publicKey,
        seed: GREETING_SEED,
        newAccountPubkey: greetedPubkey,
        lamports,
        space: GREETING_SIZE,
        programId,
      }),
    );
    await sendAndConfirmTransaction(connection, transaction, [payer]);
  }
}

客戶端再調(diào)用 sayHello 函數(shù)向鏈上程序發(fā)送交易。一個交易可以包含一個或多個不同的指令,當(dāng)前該交易包含了一個指令,指令中帶有要調(diào)用鏈上程序的 Program Id 以及客戶端要交互的賬戶地址。需要注意的是,如果交易中包含多個不同的指令,其中有一個指令執(zhí)行失敗,那么所有指令所做的操作都會被還原。

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),
    [payer],
  );
}

最后,客戶端調(diào)用 reportGreetings 函數(shù)訪問賬戶數(shù)據(jù),查詢鏈上程序被有效調(diào)用的次數(shù)。

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)',
  );
}

1.3.2 Hello World 構(gòu)建與部署

1. 創(chuàng)建項目

使用 git clone 命令下載 example-helloworld 項目。

git clone https://github.com/solana-labs/example-helloworld.git
cd example-helloworld

2. 構(gòu)建鏈上程序

運(yùn)行以下命令,在 program-rust 目錄下構(gòu)建鏈上程序。

cd src/program-rust/
cargo build-bpf

構(gòu)建完成后,src/program-rust/target/deploy 目錄下的 helloworld.so 就是可在 Solana 集群部署的鏈上程序的 BPF 字節(jié)碼文件。

3. 啟動本地集群

當(dāng)前項目在本地集群部署運(yùn)行,因此首先選擇 localhost 集群,運(yùn)行以下命令。

solana config set --url localhost

本地集群設(shè)置成功,會出現(xiàn)以下內(nèi)容。

Config File: ~/.config/solana/cli/config.yml
RPC URL: http://localhost:8899
WebSocket URL: ws://localhost:8900/ (computed)
Keypair Path: ~/.config/solana/id.json
Commitment: confirmed

再運(yùn)行以下命令,啟動 localhost 集群。

solana-test-validator

看到以下內(nèi)容,代表本地集群已成功啟動。

Ledger location: test-ledger
Log: test-ledger/validator.log
Identity: A4HuRgmABNCe94epY2mU7q6WqEHCo2B9iBFE5Yphiw5u
Genesis Hash: 96TF9n1uuyFv4rAKECffA61jLrgYjMjNRZ3hJpP6HSr7
Version: 1.7.18
Shred Version: 13390
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899
? 00:00:42 | Processed Slot: 45430 | Confirmed Slot: 45430 | Finalized Slot: 45398 | Snapshot Slot: 45300 | Transactions: 45452 | ◎499.772930000

4. 部署鏈上程序

運(yùn)行以下命令,在 localhost 集群部署鏈上程序。

solana program deploy target/deploy/helloworld.so

// Program Id: 6AArMEBpFhhtU2mBnEMEPeEH7xkhfUwPseUeG4fhLYto

鏈上程序部署成功會返回 Program Id,它類似于以太坊智能合約的地址。

5. 調(diào)用鏈上程序

helloworld 已成功部署,可以與它進(jìn)行交互了!example-helloworld 項目提供了一個簡單的客戶端,在運(yùn)行客戶端之前先安裝依賴軟件包。

npm install

由于我們調(diào)整了鏈上程序的構(gòu)建方式,沒有使用該項目默認(rèn)的 npm run build:program-rust 命令,因此需要修改 client 目錄下的 hello_world.ts 文件,將第 48 行代碼定義的變量 PROGRAM_PATH 的路徑由“../../dist/program”改為“../program-rust/target/deploy”。 再運(yùn)行以下命令,啟動客戶端去調(diào)用鏈上程序。

npm run start

客戶端成功調(diào)用鏈上程序,輸出內(nèi)容如下所示。如果再次運(yùn)行客戶端,第 10 行所顯示的次數(shù)會加一。至此,我們已經(jīng)成功在 Solana 集群部署鏈上程序并與之交互了。

> helloworld@0.0.1 start
> ts-node src/client/main.ts

Let's say hello to a Solana account...
Connection to cluster established: http://localhost:8899 { 'feature-set': 3179062686, 'solana-core': '1.6.23' }
Using account 4xRm2FYmRB8WdxJk6nXicVMgsPnsxChEnpQwFDGwdcSS containing 499999999.93435186 SOL to pay for fees
Using program 6AArMEBpFhhtU2mBnEMEPeEH7xkhfUwPseUeG4fhLYto
Creating account Eq7bcsg5p6AaYiPnfiia99ESsuq4B4jYpVbWZhQ94Zvy to say hello to
Saying hello to Eq7bcsg5p6AaYiPnfiia99ESsuq4B4jYpVbWZhQ94Zvy
Eq7bcsg5p6AaYiPnfiia99ESsuq4B4jYpVbWZhQ94Zvy has been greeted 1 time(s)
Success

如果沒有輸出期望值,請首先確認(rèn)是否已正確啟動了本地集群,構(gòu)建并部署好了鏈上程序。此外,可以運(yùn)行以下命令查看程序日志,日志包括程序日志消息以及程序失敗信息。

solana logs

包含程序失敗信息的日志如下所示,檢查日志找出程序失敗的原因。

<img src="https://learnblockchain.cn/css/default/copy.svg" /><code>Transaction executed in slot 5621:
Signature: 4pya5iyvNfAZj9sVWHzByrxdKB84uA5sCxLceBwr9UyuETX2QwnKg56MgBKWSM4breVRzHmpb1EZQXFPPmJnEtsJ
Status: Error processing Instruction 0: Program failed to complete
Log Messages:
  Program G5bbS1ipWzqQhekkiCLn6u7Y1jJdnGK85ceSYLx2kKbA invoke [1]
  Program log: Hello World Rust program entrypoint
  Program G5bbS1ipWzqQhekkiCLn6u7Y1jJdnGK85ceSYLx2kKbA consumed 200000 of 200000 compute units
  Program failed to complete: exceeded maximum number of instructions allowed (200000) at instruction #334
  Program G5bbS1ipWzqQhekkiCLn6u7Y1jJdnGK85ceSYLx2kKbA failed: Program failed to complete

1.4 本章小節(jié)

本章對 Solana 區(qū)塊鏈的基本概念進(jìn)行了簡要介紹,Solana 的智能合約叫做鏈上程序。在開始 Solana 鏈上程序開發(fā)之前,需要先安裝和配置相關(guān)的編程環(huán)境,我們著重介紹了 Solana CLI 的安裝和配置。

Hello World 是一個官方演示項目,通過對這個項目源碼的解讀,我們了解了如何使用 Rust 開發(fā)鏈上程序,并使用 Solana CLI 來構(gòu)建與部署,以及使用 Solana JavaScript SDK 與鏈上程序進(jìn)行交互。

免責(zé)聲明:本文只為提供市場訊息,所有內(nèi)容及觀點僅供參考,不構(gòu)成投資建議,不代表本站觀點和立場。投資者應(yīng)自行決策與交易,對投資者交易形成的直接或間接損失,作者及本站將不承擔(dān)任何責(zé)任。!
Tag:Solana  

你可能感興趣的文章

幣圈快訊

  • 馬斯克身價暴跌調(diào)侃自己是“前萬億富翁”

    2026-07-26 08:49
    特斯拉(TSLA.O)股價本周累跌近20%,收于313.03美元/股,創(chuàng)下2022年以來最大單周跌幅;SpaceX(SPCX.O)則收于115.07美元/股,為該公司上個月IPO以來的最低水平。 彭博億萬富翁指數(shù)的數(shù)據(jù)顯示,馬斯克的個人財富在短短五個交易日內(nèi)蒸發(fā)了約1300億美元(約合8800億元人民幣),而就在幾周前,他剛剛成為人類歷史上首位身家突破1萬億美元的富豪。馬斯克本人在社交平臺上調(diào)侃自己是“(前)萬億富翁”。
  • 若BTC跌破61237美元主流CEX累計多單清算強(qiáng)度將達(dá)6.08億美元

    2026-07-26 08:30
    據(jù)Coinglass數(shù)據(jù)顯示,若BTC跌破61,237美元,主流CEX累計多單清算強(qiáng)度將達(dá)6.08億美元。反之,若BTC突破67,045美元,主流CEX累計空單清算強(qiáng)度將達(dá)6.07億美元。
  • 趙長鵬:長期投資可采用DCA定投策略

    2026-07-26 08:27
    趙長鵬在X平臺轉(zhuǎn)發(fā)此前關(guān)于“長期持有應(yīng)在牛市還是熊市尋找最佳入場點”的帖子,并回復(fù)“DCA”。 DCA即Dollar-CostAveraging(定期定額投資),指投資者按照固定周期投入資金,通過分批買入降低單一時點價格波動對持倉成本的影響。 趙長鵬同時表示,如果不了解這一術(shù)語,可以自行搜索學(xué)習(xí),并稱掌握基本金融術(shù)語十分重要。
  • 恐慌與貪婪指數(shù)為26市場仍處于恐慌狀態(tài)

    2026-07-26 08:11
    7月26日,據(jù)Alternative數(shù)據(jù),今日加密貨幣恐慌與貪婪指數(shù)為26(昨日為27),市場仍處于恐慌狀態(tài)。注:恐慌指數(shù)閾值為0-100,包含指標(biāo):波動性(25%)+市場交易量(25%)+社交媒體熱度(15%)+市場調(diào)查(15%)+比特幣在整個市場中的比例(10%)+谷歌熱詞分析(10%)。
  • Hyperliquid單日收取140萬美元手續(xù)費(fèi)銷毀120萬美元HYPE

    2026-07-26 08:06
    據(jù)OnchainLens監(jiān)測,Hyperliquid在過去一天內(nèi)收取了140萬美元手續(xù)費(fèi),并銷毀了20.64萬枚HYPE(價值120萬美元)歷史累計銷毀量達(dá)4727萬枚HYPE(價值27.6億美元),占10億枚最大供應(yīng)量的4.73%
  • 查看更多
更多

熱門幣種

  • 幣種
    最新價格
    24H漲跌幅
  • bitcoin BTC 比特幣

    BTC

    比特幣

    $ 64374.36¥ 435827.29
    +0.34%
  • ethereum ETH 以太坊

    ETH

    以太坊

    $ 1874.81¥ 12692.83
    +0.72%
  • tether USDT 泰達(dá)幣

    USDT

    泰達(dá)幣

    $ 0.9991¥ 6.7641
    +0.01%
  • binance-coin BNB 幣安幣

    BNB

    幣安幣

    $ 568.83¥ 3851.09
    +0.7%
  • usdc USDC USD Coin

    USDC

    USD Coin

    $ 1.0008¥ 6.7756
    +0%
  • ripple XRP 瑞波幣

    XRP

    瑞波幣

    $ 1.098¥ 7.4336
    +0.57%
  • solana SOL Solana

    SOL

    Solana

    $ 74.4926¥ 504.32
    +0.77%
  • tron TRX 波場

    TRX

    波場

    $ 0.3315¥ 2.2443
    +0.21%
  • hyperliquid HYPE Hyperliquid

    HYPE

    Hyperliquid

    $ 58.1606¥ 393.75
    +1.27%
  • dogecoin DOGE 狗狗幣

    DOGE

    狗狗幣

    $ 0.071741¥ 0.4857
    +3.06%
凭祥市| 湖州市| 平顶山市| 印江| 万州区| 河东区| 皮山县| 南溪县| 枣强县| 宁明县| 元阳县| 彝良县| 曲沃县| 德令哈市| 仙游县| 曲沃县| 怀安县| 屏东县| 洞口县| 宣武区| 黑龙江省| 阿克陶县| 宁南县| 红河县| 会理县| 兖州市| 中西区| 平塘县| 嘉峪关市| 疏附县| 澳门| 五莲县| 德庆县| 崇信县| 汾西县| 新安县| 祁东县| 巴彦淖尔市| 西城区| 依安县| 灵川县|