使用Solana主网账户和程序(合约)

通常,本地测试依赖于默认情况下本地验证器上不可用的程序(合约)和帐户。Solana CLI允许:

  • 下载程序(合约)和帐户
  • 将程序(合约)和帐户加载到本地验证器

如何从主网下载帐户

可以将JUP代币铸币帐户下载到本地文件中:

# 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 jup.json JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN

然后通过在启动验证器时(在本地集群上)传递帐户的文件和目标地址将其加载到你的本地网络:

# solana-test-validator --account <address to load the account to> <path to account file> --reset
solana-test-validator --account JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN jup.json --reset

同样,也可以下载 Openbook 程序:

# solana program dump -u <source cluster> <address of account to fetch> <destination file name/path>
solana program dump -u m srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX openbook.so

然后通过在启动验证器时(在本地集群上)传递程序的文件和目标地址将其加载到你的本地网络:

# solana-test-validator --bpf-program <address to load the program to> <path to program file> --reset
solana-test-validator --bpf-program srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX openbook.so --reset

参考

Using Mainnet Accounts and Programs

订阅Solana事件

Solana提供了一个基于Websocket的发布/订阅RPC接口,你可以在其中监听某些事件。你无需每隔一段时间ping一个HTTP端点来获取频繁的更新,而是可以只在更新事件发生时接收这些更新。

当你创建新的连接(Connection)实例时,Solana的web3 Connection 会生成一个websocket端点并注册一个websocket客户端(请参阅此处的源代码)。

Connection类公开了发布pub/订阅sub方法 – 它们都以on开头,就像事件发射器一样。当你调用这些监听器方法时,它会向该Connection实例的websocket客户端注册一个新的订阅。下面我们使用的示例发布/订阅方法是onAccountChange。回调将通过参数提供更新的状态数据(请参阅AccountChangeCallback作为示例)。

/* subscribe-to-events.ts */
import { clusterApiUrl, Connection, Keypair } from "@solana/web3.js";

(async () => {
  // 建立到开发网devnet的新连接 - 连接到开发网devnet的websocket客户端也在此处注册
  const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

  // 创建一个测试钱包来监听事件
  const wallet = Keypair.generate();

  // 注册一个回调函数来来监听这个钱包的账户变化信息(即websocket订阅)
  connection.onAccountChange(
    wallet.publicKey,
    (updatedAccountInfo, context) =>
      console.log("Updated account info: ", updatedAccountInfo),
    "confirmed",
  );
})();

参考

Subscribing to Events

获取测试用SOL币

当你在本地工作时,你需要一些SOL才能进行交易。在非主网环境中,你可以通过将SOL空投到你的地址来接收SOL:

/* TS使用grill库 */
import {
  address,
  lamports,
  airdropFactory,
  createSolanaClient,
  LAMPORTS_PER_SOL,
} from "gill";

const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient(
  {
    urlOrMoniker: "devnet", // or `localnet`, etc
  },
);

const wallet = address("nick6zJc6HpW3kfBm4xS2dmbuVRyb5F3AnUvj5ymzR5");

const { value: initialBalance } = await rpc.getBalance(wallet).send();
console.log("Initial balance:", initialBalance);

/**
 * 注意:开发网devnet和测试网testnet有空投速率限制。
 * 强烈建议使用本地测试网localnet和本地测试验证器
 */
await airdropFactory({ rpc, rpcSubscriptions })({
  commitment: "confirmed",
  lamports: lamports(LAMPORTS_PER_SOL), // 申请1 SOL空投
  recipientAddress: wallet,
});

const { value: newBalance } = await rpc.getBalance(wallet).send();
console.log("New balance:", newBalance);

/* TS使用web3.js库 */
import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";

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

const wallet = new PublicKey("nick6zJc6HpW3kfBm4xS2dmbuVRyb5F3AnUvj5ymzR5");

/**
 * 注意:开发网devnet和测试网testnet有空投速率限制。
 * 强烈建议使用本地测试网localnet和本地测试验证器
 */
const signature = await connection.requestAirdrop(wallet, LAMPORTS_PER_SOL); // 申请1 SOL空投

const { blockhash, lastValidBlockHeight } =
  await connection.getLatestBlockhash();

// 注意:确认空投交易是非常重要的,用来确保你的钱包拿到空投
await connection.confirmTransaction({
  blockhash,
  lastValidBlockHeight,
  signature,
});

参考

Getting Test SOL

连接到Solana环境

当你进行Solana开发时,你需要连接到特定的RPC API端点。Solana有3个公共开发环境:

  • 主网beta(mainnet-beta):https://api.mainnet-beta.solana.com
  • 开发网(devnet):https://api.devnet.solana.com
  • 测试网(testnet):https://api.testnet.solana.com

使用网络昵称进行连接

使用昵称或名称连接到Solana公共RPC端点:

/* TS使用grill库 */
import { createSolanaClient } from "gill";

const { rpc, rpcSubscriptions } = createSolanaClient({
  urlOrMoniker: "devnet", // or `mainnet`, `localnet`, etc
});

/* TS使用web3.js库 */
import { clusterApiUrl, Connection } from "@solana/web3.js";

const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");

使用特定RPC URL进行连接

要连接到特定RPC API端点:本地测试网验证器或远程RPC提供程序,请使用以下命令:

/* TS使用grill库 */
import { createSolanaRpc, createSolanaRpcSubscriptions, devnet } from "gill";

const rpc = createSolanaRpc(devnet("https://api.devnet.solana.com"));

const rpcSubscriptions = createSolanaRpcSubscriptions(
  devnet("wss://api.devnet.solana.com"),
);

/* TS使用web3.js库 */
import { Connection } from "@solana/web3.js";

// 以下一行代码将连接到本地测试网验证器
const connection = new Connection("http://127.0.0.1:8899", "confirmed");

参考

Connecting to a Solana Environment

如何启动一个Solana本地验证者节点(Local Validator)

在本地测试你的程序代码比在devnet上测试更可靠,并且可以帮助你在devnet上试用之前进行测试。

你可以通过安装Solana CLI工具套件并运行以下命令来设置本地测试验证器:

solana-test-validator

使用本地测试节点的好处包括:

  • 无RPC速率限制
  • 无空投数量限制
  • 直接链上程序部署 (–bpf-program …)
  • 从公共集群克隆帐户,包括程序 (–clone …)
  • 可配置的交易历史保留 (–limit-ledger-size …)
  • 可配置的epoch长度 (–slots-per-epoch …)
  • 跳转到任意一个slot (–warp-slot …)

常见问题及解决方法

启动solana-test-validator报错Aborted (core dumped)

$ solana-test-validator
Aborted (core dumped)

你可以使用--log选项查看具体错误信息:

$ solana-test-validator --log
[2025-02-28T08:47:17.500858651Z INFO  solana_test_validator] agave-validator 2.1.14 (src:3ad46824; feat:3271415109, client:Agave)
[2025-02-28T08:47:17.500903233Z INFO  solana_test_validator] Starting validator with: ArgsOs {
        inner: [
            "solana-test-validator",
            "--log",
        ],
    }
[2025-02-28T08:47:17.500940423Z WARN  solana_perf] CUDA is disabled
[2025-02-28T08:47:17.500970698Z INFO  solana_perf] AVX detected
[2025-02-28T08:47:17.500975929Z ERROR solana_perf] Incompatible CPU detected: missing AVX2 support. Please build from source on the target
Aborted (core dumped)

以上报错表明你的CPU不支持AVX2指令集。运行以下命令,如果没有任何输出就表明你的CPU不支持AVX2指令集:

$ grep avx2 /proc/cpuinfo

AVX2(Advanced Vector Extensions 2)是 Intel 和 AMD 的现代处理器中提供的一种 SIMD(Single Instruction, Multiple Data)指令集扩展。AVX2是AVX(Advanced Vector Extensions)指令集的后续版本,增加了更多的指令以提高数据并行性和处理效率。

主要特点:

  • SIMD计算:AVX2 提供对128位和256位宽度的SIMD指令支持,用于并行处理多个数据。
  • 整数指令扩展:与AVX相比,AVX2不仅扩展了对浮点数运算的支持,还增强了对整数运算的支持,允许更高效的向量化处理。
  • 增强的性能:AVX2在执行大规模数据计算时,特别是在进行矩阵运算、图形处理、加密、压缩算法等方面能显著提升性能。

哪些CPU支持AVX2:

  • Intel: 从**Haswell(第四代Core系列处理器)**开始,Intel处理器支持AVX2。
  • AMD: 从**Steamroller(Kaveri架构)**及后续处理器开始,AMD也开始支持AVX2。

因此,如果你的CPU是Intel Haswell架构及以后的系列,或者是AMD Kaveri架构及以后的系列,那么它就支持AVX2指令集。

如果你的CPU不支持AVX2指令集,那么方法一是下载Solana源码自己构建,方法二是使用Docker运行非AVX版本的Solana。

方法一,下载Solana源码自己构建

步骤如下:

1 先更新一下系统的软件包

对于Ubuntu:

$ sudo apt-get update

2 安装依赖项

$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make

3 安装Rust

$ curl https://sh.rustup.rs -sSf | sh
$ source $HOME/.cargo/env
$ rustup component add rustfmt

4 下载Solana源码

$ mkdir ~/solana && cd ~/solana
$ git clone https://github.com/solana-labs/solana.git

5 构建

$ cd solana

切换到稳定版本分支:

$ git checkout v1.18.26

执行构建:

$ cargo clean
$ export RUST_REED_SOLOMON_ERASURE_ARCH=native
$ export RUSTFLAGS="-C target-feature=-avx2"
$ ./scripts/cargo-install-all.sh .

6 运行solana-test-validator

我们是从克隆Solana的git存储库构建得到二进制文件,就不需要先执行solana-install init命令了,直接执行solana-test-validator启动一个本地验证者节点:

$ ./target/release/solana-test-validator

如果输出如下信息:

Ledger location: test-ledger
Log: test-ledger/validator.log
⠤ Initializing...                                                                                                                                                                                               Waiting for fees to stabilize 1...
Identity: H4gRUMNMJfd8fsVDhnvmnt4SenqELPdtUAEuGFLBFj5c
Genesis Hash: 4NHw8wya1tD2eFbLPpRwtVeAKBAKSd8EiARk8h3u3QGj
Version: 1.18.26
Shred Version: 47462
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

表示本地测试网启动成功!

通过上述步骤构建得到的Solana的可执行的二进制文件在~/solana/solana/target/release/和~/solana/solana/bin/里。可以把以下这行代码写入家目录里的.profile文件里,就可以直接使用可执行的二进制文件的名字来运行它了:

export PATH="~/solana/solana/bin:$PATH"

使.profile文件的修改生效:

$ source ~/.profile

7 创建一个Solana账户

执行以下命令创建一个Solana账户:

$ solana-keygen new

要记住生成的Solana账户的种子和公钥。

8 在本地测试网申请空投(水龙头币)

连接到本地测试网:

$ solana config set --url http://localhost:8899

在本地测试网请求空投:

$ solana airdrop 1

返回如下结果:

Requesting airdrop of 1 SOL

Signature: 5a6YXCwMVgwmxBz7p4g2LnTuhK2hVKqGW9QfUguJmruxLDvWKwq1xx1W2XuUiAJuqLmxEtPUAgQcri5RRjjouNQP

500000001 SOL

可以看到我们的账号里有500000001个SOL。因为默认情况下,本地测试网会向你的本地钱包账户(~/.config/solana/id.json)空投50000000个SOL,以便你能够进行测试、部署智能合约和交易。 可以使用以下命令查询本地钱包账户的余额:

$ solana balance
500000001 SOL

也可以通过RPC接口查询账户的余额:

curl --location --request POST 'http://localhost:8899' \
--header 'Content-Type: application/json' \
--data-raw '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getBalance",
    "params": [
        "AoKpX1XF22sJWpuv2gE36YEYekQV5EeQghyPSnYvLTkv"
    ]
}'

其中

  • http://localhost:8899是本地测试网的网址
  • AoKpX1XF22sJWpuv2gE36YEYekQV5EeQghyPSnYvLTkv是账户的公钥,也是账户的地址

返回如下结果:

{"jsonrpc":"2.0","result":{"context":{"apiVersion":"1.18.26","slot":4506},"value":500000001000000000},"id":1}

可以看到余额是500000001000000000,因为SOL的精度是10^9,所以也就是500000001个SOL。

方法二,使用Docker运行非AVX版本的Solana

我暂时没有在dockerhub网站找到非AVX版本的Solana镜像。

参考

How to Start a Local Validator

https://solana.stackexchange.com/questions/4703/how-to-fix-solana-test-validator-illegal-instruction-core-dumped-error-even-af

https://github.com/solana-labs/solana/issues/21233

https://stackoverflow.com/questions/71770717/anchor-test-without-avx2-cpu