欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

1.1 Solana 簡(jiǎn)介

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

Solana 的共識(shí)算法采用 PoH(歷史證明),其核心是一個(gè)去中心化時(shí)鐘,該時(shí)鐘旨在解決缺乏單個(gè)可信賴時(shí)間源在分布式網(wǎng)絡(luò)中的時(shí)間問題。PoH 免除了在節(jié)點(diǎn)網(wǎng)絡(luò)中廣播時(shí)間戳的需求,從而提高整個(gè)網(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)行時(shí)去執(zhí)行智能合約的邏輯。此外,基于 Solana JSON RPC API,官方提供了諸多 SDK 用于客戶端與 Solana 鏈上數(shù)據(jù)交互。

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

1.1.2 賬戶模型

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

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

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

表 1-1 賬戶定義字段

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

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

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

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

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

1.2.1 安裝 Solana CLI

Solana CLI 是與 Solana 集群進(jìn)行交互的命令行管理工具,包含節(jié)點(diǎn)程序 solana-validator、密鑰對(duì)生成工具 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)"

如果安裝成功,會(huì)出現(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 中,并會(huì)自動(dòng)將該路徑加入 ~/.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 的版本號(hào)、版本哈希等信息,代表環(huán)境變量設(shè)置成功。如果未看到這些信息,請(qǐng)檢查相關(guān)文件中 PATH 環(huán)境變量設(shè)置的路徑是否正確。

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

solana-install update

1.2.2 配置 Solana CLI

1. 連接到集群

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

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

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

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

2. 創(chuàng)建賬戶

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

solana-keygen new

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

solana-keygen pubkey

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

solana balance

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

solana airdrop 2

1.3 第一個(gè) Solana 項(xiàng)目——Hello World

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

1.3.1 Hello World 源碼解讀

example-helloworld 項(xiàng)目的目錄結(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 所示,實(shí)現(xiàn)了將程序被調(diào)用次數(shù)存儲(chǔ)在鏈上賬戶中。

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

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

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

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

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

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

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

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

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

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

代碼清單 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. 客戶端程序源碼解讀

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

在 client 目錄下,客戶端執(zhí)行的入口是 main.ts 文件,它按特定的順序執(zhí)行任務(wù),每個(gè)任務(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ù)來確保有一個(gè)有支付能力的賬戶。

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 中加載已部署程序的密鑰對(duì)(此操作前需先構(gòu)建鏈上程序,詳見 1.3.2 節(jié)),并使用密鑰對(duì)的公鑰來獲取程序賬戶。如果程序不存在,客戶端會(huì)報(bào)錯(cuò)并停止執(zhí)行。如果程序存在,將創(chuàng)建一個(gè)新賬戶來存儲(chǔ)狀態(tài),并以該程序作為新賬戶所有者。這里新賬戶存儲(chǔ)的狀態(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ā)送交易。一個(gè)交易可以包含一個(gè)或多個(gè)不同的指令,當(dāng)前該交易包含了一個(gè)指令,指令中帶有要調(diào)用鏈上程序的 Program Id 以及客戶端要交互的賬戶地址。需要注意的是,如果交易中包含多個(gè)不同的指令,其中有一個(gè)指令執(zhí)行失敗,那么所有指令所做的操作都會(huì)被還原。

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)建項(xiàng)目

使用 git clone 命令下載 example-helloworld 項(xiàng)目。

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)本地集群

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

solana config set --url localhost

本地集群設(shè)置成功,會(huì)出現(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)行以下命令,啟動(dòng) localhost 集群。

solana-test-validator

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

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

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

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

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

npm install

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

npm run start

客戶端成功調(diào)用鏈上程序,輸出內(nèi)容如下所示。如果再次運(yùn)行客戶端,第 10 行所顯示的次數(shù)會(huì)加一。至此,我們已經(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

如果沒有輸出期望值,請(qǐng)首先確認(rèn)是否已正確啟動(dòng)了本地集群,構(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é)

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

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

聲明:文章內(nèi)容不代表本站觀點(diǎn)及立場(chǎng),不構(gòu)成本平臺(tái)任何投資建議。本文內(nèi)容僅供參考,風(fēng)險(xiǎn)自擔(dān)!
Tag:Solana  

你可能感興趣的文章

幣圈快訊

  • CircleCEO:區(qū)塊鏈網(wǎng)絡(luò)是互聯(lián)網(wǎng)的新操作系統(tǒng)層

    2025-06-09 23:53
    金色財(cái)經(jīng)報(bào)道,Circle聯(lián)合創(chuàng)始人兼首席執(zhí)行官JeremyAllaire在X平臺(tái)發(fā)文表示,加密保護(hù)、全球可用的數(shù)據(jù)、交易和計(jì)算網(wǎng)絡(luò)是互聯(lián)網(wǎng)的新操作系統(tǒng)層(區(qū)塊鏈網(wǎng)絡(luò)),Circle正在其上構(gòu)建互聯(lián)網(wǎng)金融系統(tǒng)(穩(wěn)定幣網(wǎng)絡(luò))。
  • 美股Circle漲幅收窄至2.72%,暫報(bào)110.64美元

    2025-06-09 23:43
    金色財(cái)經(jīng)報(bào)道,美股Circle漲幅收窄至2.72%,暫報(bào)110.64美元,市值回落至247.15億美元。此前漲幅曾一度擴(kuò)大至24.22%,股價(jià)突破138美元。
  • 亞特蘭大聯(lián)儲(chǔ)GDPNow模型預(yù)計(jì)美國(guó)第二季度GDP增速為3.8%

    2025-06-09 23:42
    金色財(cái)經(jīng)報(bào)道,亞特蘭大聯(lián)儲(chǔ)GDPNow模型預(yù)計(jì)美國(guó)第二季度GDP增速為3.8%,與此前預(yù)期一致。
  • 上市公司KULR尋求通過普通股發(fā)行募資3億美元增持比特幣

    2025-06-09 23:42
    金色財(cái)經(jīng)報(bào)道,上市公司KULR正尋求通過在市場(chǎng)上發(fā)行普通股籌集高達(dá)3億美元的資金,該公司目前持有800個(gè)比特幣,并且計(jì)劃將募集的資金用于一般公司用途,包括購買更多比特幣。據(jù)悉,KULR還通過兩份協(xié)議租賃了5,500臺(tái)S-19比特幣礦機(jī),總額超過400萬美元。
  • 上市公司KULR尋求通過普通股發(fā)行募資3億美元以增持比特幣

    2025-06-09 23:40
    ChainCatcher消息,上市公司KULR正尋求通過在市場(chǎng)上發(fā)行普通股籌集高達(dá)3億美元的資金,該公司目前持有800個(gè)比特幣,并且計(jì)劃將募集的資金用于一般公司用途,包括購買更多比特幣。據(jù)悉,KULR還通過兩份協(xié)議租賃了5,500臺(tái)S-19比特幣礦機(jī),總額超過400萬美元。
  • 查看更多