Lập trình ở Local

Khởi chạy Local Validator

Kiểm thử program của bạn trên máy cá nhân sẽ nhanh và đáng tin cậy hơn nhiều so với devnet. Quá trình này giúp bạn có thể kiểm tra chương trình trước khi triển khai và kiểm thứ chúng trên devnet.

Bạn có thể thiết lập local-test-validator bằng cách cài đặt bộ công cụ solana và chạy lệnh sau:

solana-test-validator

Lợi ích của việc chạy local-test-validator gồm:

  • Không giới hạn truy vấn RPC
  • Không giới hạn số lượng SOL nhận được để kiểm thử
  • Triển khai trực tiếp program lên on-chain (--bpf-program ...)
  • Sao chép account từ các mạng công cộng, bao gồm cả các program (--clone ...)
  • Có thể điều chỉnh số lượng lịch sử transaction (--limit-ledger-size ...)
  • Có thể điều chỉnh độ dài epoch (--slots-per-epoch ...)
  • Nhảy đến bấy kỳ chỗ trống nào (--warp-slot ...)

Kết nối đến môi trường

Một khi bắt đầu làm việc với môi trường phát triển ứng dụng trên Solana, bạn sẽ cần phải kết nối ứng dụng của bạn đến một điểm RPC API cụ thể. Solana có 3 môi trường công cộng cho quá trình phát triển ứng dụng:

  • mainnet-beta: https://api.mainnet-beta.solana.com
  • devnet: https://api.devnet.solana.com
  • testnet: https://api.testnet.solana.com
Press </> button to view full source
import { clusterApiUrl, Connection } from "@solana/web3.js";

(async () => {
  const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
})();
from solana.rpc.api import Client

client = Client("https://api.mainnet-beta.solana.com")
#include "solana.hpp"

using namespace many::solana;

int main() {
    Connection connection("https://api.mainnet-beta.solana.com");
    return 0;
}
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;

fn main() {
    let rpc_url = String::from("https://api.mainnet-beta.solana.com");
    let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
}
solana config set --url https://api.mainnet-beta.solana.com

Cuối cùng bạn cũng có thể kết nối đến các mạng riêng, hoặc từ một điểm truy cập cá nhân, hoặc từ một dịch vụ từ xa ví dụ như:

Press </> button to view full source
import { Connection } from "@solana/web3.js";

(async () => {
  // This will connect you to your local validator
  const connection = new Connection("http://127.0.0.1:8899", "confirmed");
})();
from solana.rpc.api import Client

client = Client("http://127.0.0.1:8899")
#include "solana.hpp"

using namespace many::solana;

int main() {
    Connection connection("http://127.0.0.1:8899");
    return 0;
}
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;

fn main() {
    let rpc_url = String::from("http://127.0.0.1:8899");
    let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
}
solana config set --url http://privaterpc.com

Lắng nghe các sự kiện

Websockets cung cấp một giao diện pub/sub để bạn có thể lắng nghe các sự kiện cụ thể. Thay vì liên tục gọi vào các điểm thông tin thông qua HTTP để thường xuyên cập nhật dữ liệu, bạn có thể nhận được dữ liệu cập nhật mỗi khi có thay đổi xảy ra.

Connectionopen in new window trong web3 của Solana sẽ chủ động tạo ra một kết nối websocket mỗi khi bạn tạo mới Connection (chi tiết mã nguồn tại đâyopen in new window).

Lớp Connection sẽ cung cấp các phương thức pub/sub - tất cả chúng đều bắt đầu với tiền tố on, giống như các emitter. Khi bạn gọi vào một phương thức nghe, nó sẽ đăng ký một sự kiện mới vào websocket người dùng của Connection vừa tạo. Ví dụ cho phương thức pub/sub bên dưới sẽ sử dụng onAccountChangeopen in new window. Hàm gọi lại (callback) sẽ nhận các tham số và cập nhật lại trạng thái mới (tham khảo ví dụ AccountChangeCallbackopen in new window).

Press </> button to view full source
import { clusterApiUrl, Connection, Keypair } from "@solana/web3.js";

(async () => {
  // Establish new connect to devnet - websocket client connected to devnet will also be registered here
  const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

  // Create a test wallet to listen to
  const wallet = Keypair.generate();

  // Register a callback to listen to the wallet (ws subscription)
  connection.onAccountChange(
    wallet.publicKey(),
    (updatedAccountInfo, context) =>
      console.log("Updated account info: ", updatedAccountInfo),
    "confirmed"
  );
})();
import asyncio
from solders.keypair import Keypair
from solana.rpc.websocket_api import connect

async def main():
    async with connect("wss://api.devnet.solana.com") as websocket:
        # Create a Test Wallet
        wallet = Keypair()
        # Subscribe to the Test wallet to listen for events
        await websocket.account_subscribe(wallet.pubkey())
        # Capture response from account subscription 
        first_resp = await websocket.recv()
        print("Subscription successful with id {}, listening for events \n".format(first_resp.result))
        updated_account_info = await websocket.recv()
        print(updated_account_info)
        
asyncio.run(main())
// clang++ on_account_change.cpp -o on_account_change -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  Connection connection("https://api.devnet.solana.com");

  auto key_pair = Keypair::generate();

  int subscriptionId = connection.on_account_change(key_pair.public_key, [&](Result<Account> result) {
    Account account = result.unwrap();
    std::cout << "owner = " << account.owner.to_base58() << std::endl;
    std::cout << "lamports = " << account.lamports << std::endl;
    std::cout << "data = " << account.data << std::endl;
    std::cout << "executable = " << (account.executable ? "true" : "false") << std::endl;
  });

  sleep(1);

  std::string tx_hash = connection.request_airdrop(key_pair.public_key).unwrap();
  std::cout << "tx hash = " << tx_hash << std::endl;

  for (int i = 0; i < 10; i++) {
    connection.poll();
    sleep(1);
  }

  connection.remove_account_listener(subscriptionId);

  return 0;
}
use solana_client::pubsub_client::PubsubClient;
use solana_client::rpc_config::RpcAccountInfoConfig;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::signature::{Keypair, Signer};

fn main() {
    let wallet = Keypair::new();
    let pubkey = Signer::pubkey(&wallet);
    let ws_url = String::from("wss://api.devnet.solana.com/");
    println!("{}", ws_url);
    if let Ok(subscription) = PubsubClient::account_subscribe(
        &ws_url,
        &pubkey,
        Some(RpcAccountInfoConfig {
            encoding: None,
            data_slice: None,
            commitment: Some(CommitmentConfig::confirmed()),
        }),
    ) {
        let (mut ws_client, receiver) = subscription;
        println!("Subscription successful, listening for events");
        let handle = std::thread::spawn(move || loop {
            println!("Waiting for a message");
            match receiver.recv() {
                Ok(message) => println!("{:?}", message),
                Err(err) => {
                    println!("Connection broke with {:}", err);
                    break;
                }
            }
        });
        handle.join().unwrap();
        ws_client.shutdown().unwrap()
    } else {
        println!("Errooooor");
    }
}

Nhận SOL để kiểm thử

Khi bạn làm việc trên môi trường địa phương, bạn sẽ phải cần một ít SOL để gửi transaction. Trong các môi trường không phải mainnet, bạn có thể nhận được SOL miễn phí.

Press </> button to view full source
import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";

(async () => {
  const keypair = Keypair.generate();

  const connection = new Connection("http://127.0.0.1:8899", "confirmed");

  const signature = await connection.requestAirdrop(
    keypair.publicKey,
    LAMPORTS_PER_SOL
  );
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
  await connection.confirmTransaction({
      blockhash,
      lastValidBlockHeight,
      signature
    });
})();
from solders.keypair import Keypair
from solana.rpc.api import Client

wallet = Keypair()

client = Client("https://api.devnet.solana.com")

#Input Airdrop amount in LAMPORTS
client.request_airdrop(wallet.pubkey(), 1000000000)

#Airdrops 1 SOL
// clang++ request_airdrop.cpp -o request_airdrop -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  Connection connection("https://api.devnet.solana.com");

  auto key_pair = Keypair::generate();

  std::string tx_hash = connection.request_airdrop(key_pair.public_key).unwrap();

  std::cout << "tx hash = " << tx_hash << std::endl;

  return 0;
}
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::native_token::LAMPORTS_PER_SOL;
use solana_sdk::signature::{Keypair, Signer};

fn main() {
    let wallet = Keypair::new();
    let pubkey = Signer::pubkey(&wallet);
    let rpc_url = String::from("https://api.devnet.solana.com");
    let client = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
    match client.request_airdrop(&pubkey, LAMPORTS_PER_SOL) {
        Ok(sig) => loop {
            if let Ok(confirmed) = client.confirm_transaction(&sig) {
                if confirmed {
                    println!("Transaction: {} Status: {}", sig, confirmed);
                    break;
                }
            }
        },
        Err(_) => println!("Error requesting airdrop"),
    };
}
solana airdrop 1

# Return
# "1 SOL"

Sử dụng Accounts và Programs trên Mainnet

Thường xuyên, các bài kiểm thử trên môi trường địa phương sẽ dùng đến các account và program chỉ sẵn có trên mainnet. Solana CLI cho phép:

  • Tải xuống Programs và Accounts
  • Cài đặt Programs và Accounts vào local validator

Làm thế nào để cài đặt accounts từ mainnet

Bạn có thể tải xuống mint account của SRM vào một tập tin:

Press </> button to view full source
# solana account -u <source cluster> --output <output format> --output-file <destination file name/path> <address of account to fetch>
solana account -u m --output json-compact --output-file SRM_token.json SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt

Sau đó, cài đặt nó vào môi trường localnet của bạn bằng cách truyền tập tin ở trên và địa chỉ đích (trên môi trường địa phương) khi bắt đầu khởi chạy validator:

Press </> button to view full source
# solana-test-validator --account <address to load the account to> <path to account file> --reset
solana-test-validator --account SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt SRM_token.json --reset

Làm thế nào để cải đặt programs từ mainnet

Tương tự, bạn phải tải xuống program của Serum Dex v3:

Press </> button to view full source
# solana program dump -u <source cluster> <address of account to fetch> <destination file name/path>
solana program dump -u m 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin serum_dex_v3.so

Cài đặt nó vào localnet được thực hiện bằng cách truyền tập tin program và địa chỉ đích (trên môi trường đại phương) khi bắt đầu khởi chạy validator:

Press </> button to view full source
# solana-test-validator --bpf-program <address to load the program to> <path to program file> --reset
solana-test-validator --bpf-program 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin serum_dex_v3.so --reset
Last Updated:
Contributors: Partially Sorted, tuphan-dn