Solana 核心概念全解析:账户、交易、合约与租约,高流量区块链技术揭秘!

目录

[1.Solana 核心概念简述](#1.Solana 核心概念简述)

[1.1. 账户(Account)](#1.1. 账户(Account))

[1.2. 交易(Transaction)](#1.2. 交易(Transaction))

[1.3. 交易指令(Instruction)](#1.3. 交易指令(Instruction))

[1.4. SPL 代币](#1.4. SPL 代币)

[1.5. 合约(Program)](#1.5. 合约(Program))

[1.6. 租约(Rent)](#1.6. 租约(Rent))

2通过RPC与Solana交互

2.1.配置环境

2.2.查看钱包信息

[2.3.Token 账户查询](#2.3.Token 账户查询)

[2.4.创建 Token 账户](#2.4.创建 Token 账户)

2.5.实时监控账户变动

2.6.转账操作

3.Solana的Web3.js

3.1.交易代码

3.2.输出结果

[4.通过 WalletAdatper 与钱包交互](#4.通过 WalletAdatper 与钱包交互)

[4.1 依赖和示例界面](#4.1 依赖和示例界面)

[4.2Solana 钱包 API 整理](#4.2Solana 钱包 API 整理)

4.2.1关键包和导入

[4.2.2SolongWallet 适配器集成](#4.2.2SolongWallet 适配器集成)

4.2.3钱包连接和状态管理

[4.2.4 交易操作](#4.2.4 交易操作)

[4.2.5 RPC 配置和管理](#4.2.5 RPC 配置和管理)


1.Solana 核心概念简述

Solana 是一个高性能的区块链平台,其核心概念包括 账户(Account)交易(Transaction)合约(Program)租约(Rent)。以下是对这些概念的简短易懂概括:

1.1. 账户(Account)

  • "一切皆账户":类似 Linux 系统把所有资源抽象为"文件",Solana 中所有的信息(如代币余额、合约代码等)都存储在账户对象中。

  • 账户结构

    • lamports:账户余额(Solana 的原生代币单位)。
    • data:存储的数据(对于合约账户,这里是代码;对于用户账户,这里可能是代币信息)。
    • owner:账户的所有者(通常是一个合约地址,决定谁能操作这个账户)。
    • executable:是否为可执行合约(如果是合约账户,此值为 true)。
    • rent_epoch:下次需要支付租金的周期。
  • 账户与签名

    1.2. 交易(Transaction)

    • 用户账户本质是一个 私钥,通过 Ed25519 算法生成(高效、安全、签名短)。
    • 账户地址是私钥对应的 公钥,经过 Base58 编码后变成可读形式(如 HawRVHh7t4d3H3bitWHFt25WhhoDmbJMCfWdESQQoYEy)。
    • 私钥签名用于证明对账户的控制权。
  • 定义:交易是用户与区块链交互的方式,例如转账或调用合约。

  • 组成

    • 一系列 交易指令(Instruction):指定要执行的操作、涉及的账户和数据。
    • 签名:由发起者的私钥生成,用于验证交易有效性。
    • 账户列表:交易中涉及的所有账户地址。
    • 最近区块哈希:确保交易的时效性。

1.3. 交易指令(Instruction)

  • 定义:交易的核心单元,描述具体的操作。
  • 结构
    • program_id_index:要调用的合约地址(在账户列表中的索引)。
    • accounts:操作涉及的账户。
    • data:输入的具体数据。

1.4. SPL 代币(SPL)

在以太坊中,普通代币被一个叫ERC20的提案定了规范,可以认为普通代币合约统一叫做ERC20代币。

那么Solana世界里的ERC20代币是什么呢?答案就是SPL代币。

The Solana Program Library (SPL) is a collection of on-chain programs targeting the Sealevel parallel runtime.

SPL Token是 " Solana Program Library"中的一个组成部分,叫做"Token Program",简称为SPL Token。

所有的代币都有这个合约来管理,该合约代码在 https://github.com/solana-labs/solana-program-library/tree/master/token

不同于以太坊中,一个代币就是一个合约。

SPL Token中,一个代币,仅仅是一个归Token合约管理的普通的Account对象,这个对象里面的二进制数据定义了 这个代币的基本属性

1.5. 合约(Program)

  • 类型
    • 系统合约(Native Program):由 Solana 官方提供,如 System Program(创建账户、转账)、BPF Loader Program(部署合约)。
    • 普通合约(On Chain Program):用户开发并部署的合约,如代币相关合约。
  • 特点
    • 合约是存储在账户中的可执行代码(executable = true)。
    • 用户通过交易调用合约执行逻辑。
    • Solana 的合约可以更新或销毁,销毁时存储资源会退还给部署者。

1.6. 租约(Rent)

  • 什么是租约
    • 账户需要支付"租金"来保持数据存储在区块链上,租金根据存储的数据量和时间计算。
  • 规则
    • 免租:账户余额超过"两年租金"的阈值则无需支付租金。
    • 租金不足:余额低于免租阈值或付不出租金的账户会被"垃圾收集"(删除)。
  • 与交易费用的区别
    • 租金是为存储付费。
    • 交易费用是为处理指令付费。

2通过RPC与Solana交互

2.1.配置环境

首先,将钱包配置指向 Devnet 环境:

bash 复制代码
solana config set --url https://api.devnet.solana.com

2.2.查看钱包信息

查看当前钱包地址:

bash 复制代码
solana address

获取测试网 SOL(开发资金):

bash 复制代码
solana airdrop 2

查看钱包 SOL 余额:

bash 复制代码
solana balance

查看钱包中所有 SPL Token 余额:

bash 复制代码
spl-token accounts

2.3.Token 账户查询

通过这个 curl 请求,你可以查询 Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi 这个钱包地址下,所有与 7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9 这个 SPL Token(Token 的 Mint 地址)相关的 Token 账户

bash 复制代码
curl  https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '
        {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "getTokenAccountsByOwner",
            "params": [
            "Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi",
            {
                "mint": "7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9"
            },
            {
                "encoding": "jsonParsed"
            }
            ]
        }
    '

查询结果解析:

bash 复制代码
{
    "jsonrpc": "2.0",
    "result": {
        "context": {
            "apiVersion": "2.1.13",
            "slot": 363620820
        },
        "value": [
            {
                "account": {
                    "data": {
                        "parsed": {
                            "info": {
                                "isNative": false,
                                "mint": "7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9",
                                "owner": "Czorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi",
                                "state": "initialized",
                                "tokenAmount": {
                                    "amount": "94000000000",
                                    "decimals": 9,
                                    "uiAmount": 94,
                                    "uiAmountString": "94"
                                }
                            },
                            "type": "account"
                        },
                        "program": "spl-token",
                        "space": 165
                    },
                    "executable": false,
                    "lamports": 315139280,
                    "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                    "rentEpoch": 18446744073709552000,
                    "space": 165
                },
                "pubkey": "EZhhUANUMKsRhRMArczio1kLc9axefTUAh5xofGX35AK"
            }
        ]
    },
    "id": 1
}
  • pubkeyEZhhUANUMKsRhRMArczio1kLc9axefTUAh5xofGX35AK - Token 账户公钥
  • mint7vtXvye2ECB1T5Se8E1KebNfmV7t4VkaULDjf2v1xpA9 - SPL Token 的类型标识符
  • ownerCzorr4y9oFvE3VdfCLVFuKDYxaNUG1iyQomR7kMZUuzi - 该 Token 账户的拥有者钱包地址
  • tokenAmount:当前持有的代币数量(带有小数位信息)

2.4.创建 Token 账户

为某个 SPL Token 创建关联账户(需要确保接收者有对应的 Token 账户才能接收特定代币):

bash 复制代码
spl-token create-account 9pbWQJHTSLELGekc85QHYCHozRdLo4si2nCPbMNZ2bxj --owner HybiEijLUVae5NFoiW52jCoN2bQ9TUL74wJkfPRgHxbm --fee-payer /Users/linzhihao/.config/solana/id.json

2.5.实时监控账户变动

使用 WebSocket 订阅账户变化(需要提前安装 wscat 工具):

bash 复制代码
wscat -c wss://api.devnet.solana.com

连接后发送订阅请求:

bash 复制代码
{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["HybiEijLUVae5NFoiW52jCoN2bQ9TUL74wJkfPRgHxbm",{"encoding":"jsonParsed","commitment":"finalized"}]}

监听Solana token account HybiEijLUVae5NFoiW52jCoN2bQ9TUL74wJkfPRgHxbm

2.6.转账操作

转移 SPL Token 到另一个钱包(自动为对方创建接收账户):

bash 复制代码
spl-token transfer --fund-recipient  9pbWQJHTSLELGekc85QHYCHozRdLo4si2nCPbMNZ2bxj 0.01 BBy1K96Y3bohNeiZTHuQyB53LcfZv6NWCSWqQp89TiVu
  • --fund-recipient:如果目标地址没有该Token的账户,则为其创建一个。
  • 1:转账的Token数量,1表示转1个单位的该Token。
  • BBy1K96Y3bohNeiZTHuQyB53LcfZv6NWCSWqQp89TiVu:目标收件人的Solana Public Address

3.Solana的Web3.js

3.1.交易代码

javascript 复制代码
// solana-test.js
const { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction } = require('@solana/web3.js');
const fs = require('fs'); 
const bs58 = require('bs58');


async function main() {
  try {
    // 1. 读取 id.json 文件
    const idJson = JSON.parse(fs.readFileSync('/Users/linzhihao/.config/solana/id.json', 'utf8'));
 

    // 2. 解码为 Uint8Array
    const secretKey = new Uint8Array(idJson);


    // 3. 创建 Keypair
    const keypair = Keypair.fromSecretKey(secretKey);
    console.log('✅ Loaded keypair from secret key');
    console.log(`   Address: ${keypair.publicKey.toString()}`);

    // 4. 连接到 Solana 网络
    const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
    


    // 5. Check account balance
    const balance = await connection.getBalance(keypair.publicKey);
    console.log(`✅ Current balance: ${balance / LAMPORTS_PER_SOL} SOL`);

    // If balance is too low, request an airdrop
    if (balance < 0.1 * LAMPORTS_PER_SOL) {
      console.log('⏳ Requesting airdrop of 1 SOL...');
      const airdropSignature = await connection.requestAirdrop(
        keypair.publicKey,
        1 * LAMPORTS_PER_SOL
      );
      
      // Wait for confirmation
      const latestBlockhash = await connection.getLatestBlockhash('finalized');
      await connection.confirmTransaction({
        blockhash: latestBlockhash.blockhash,
        lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
        signature: airdropSignature
      });
      
      const newBalance = await connection.getBalance(keypair.publicKey);
      console.log(`✅ New balance after airdrop: ${newBalance / LAMPORTS_PER_SOL} SOL`);
    }

    // 6. Set up recipient address for transfer (just an example address)
    const recipientAddress = new PublicKey('Ey9M2QMRfg8Tuysyh3UEdeB9NwZmRaJU5FUjKtBSNJnb');
    const transferAmount = 0.01 * LAMPORTS_PER_SOL; // 0.01 SOL
    
    console.log(`⏳ Preparing to send ${transferAmount / LAMPORTS_PER_SOL} SOL to ${recipientAddress.toString()}...`);

    // 7. Get latest blockhash
    const latestBlockhash = await connection.getLatestBlockhash('finalized');
    console.log(`✅ Fetched latest blockhash. Last Valid Height: ${latestBlockhash.lastValidBlockHeight}`);
    
    // 8. Create a transfer instruction
    const transferInstruction = SystemProgram.transfer({
      fromPubkey: keypair.publicKey,
      toPubkey: recipientAddress,
      lamports: transferAmount
    });
    
    // 9. Create a transaction message
    const message = new TransactionMessage({
      payerKey: keypair.publicKey,
      recentBlockhash: latestBlockhash.blockhash,
      instructions: [transferInstruction]
    }).compileToV0Message();
    
    // 10. Create a versioned transaction
    const transaction = new VersionedTransaction(message);
    
    // 11. Sign the transaction
    transaction.sign([keypair]);
    console.log('✅ Transaction signed');
    
    // 12. Send the transaction
    const signature = await connection.sendTransaction(transaction);
    console.log(`✅ Transaction sent with signature: ${signature}`);
    
    // 13. Confirm the transaction
    console.log('⏳ Confirming transaction...');
    await connection.confirmTransaction({
      blockhash: latestBlockhash.blockhash,
      lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
      signature: signature
    });
    console.log('✅ Transaction confirmed');
    
    // 14. Check the new balance
    const newBalance = await connection.getBalance(keypair.publicKey);
    console.log(`✅ New balance after transfer: ${newBalance / LAMPORTS_PER_SOL} SOL`);
    
  } catch (error) {
    console.error('❌ Error:', error);
  }
}

main();

3.2.输出结果

✅ Loaded keypair from secret key

Address: Ed5NC8cwDiJ7A8831DoAdELq6aouydCbywUDLg3EwC8k

✅ Current balance: 2.89027628 SOL

⏳ Preparing to send 0.01 SOL to Ey9M2QMRfg8Tuysyh3UEdeB9NwZmRaJU5FUjKtBSNJnb...

✅ Fetched latest blockhash. Last Valid Height: 351840779

✅ Transaction signed

✅ Transaction sent with signature: 2x4DEvKHvuXDtrFUfPhLL1EcicYTf1AKKuuer6gU5o2Rrt14sa85uRGgrApZJUPLJod6JdgGuezwVBbb5x3RLs7n

⏳ Confirming transaction...

✅ Transaction confirmed

✅ New balance after transfer: 2.88027128 SOL

4.通过 WalletAdatper 与钱包交互

4.1 依赖和示例界面

javascript 复制代码
npm install \
  @solana/wallet-adapter-react@0.15.35 \
  @solana/wallet-adapter-base@0.9.23 \
  @solana/wallet-adapter-wallets@0.17.0 \


npm install @solana/buffer-layout
npm install @solana/web3.js@latest
npm install @craco/craco --save-dev
npm install web-vitals

安转chrom插件Phantom

4.2Solana 钱包 API 整理

4.2.1关键包和导入

javascript 复制代码
// 核心适配器和连接
import { ConnectionProvider, WalletProvider, useConnection, useWallet } from '@solana/wallet-adapter-react';
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';

// UI 组件
import { WalletDisconnectButton, WalletMultiButton } from '@solana/wallet-adapter-react-ui';

// 特定钱包适配器
import { SolongWalletAdapter } from '@solana/wallet-adapter-solong';
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom';

// Solana Web3 工具
import { Keypair, Connection, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction } from '@solana/web3.js';

4.2.2SolongWallet 适配器集成

javascript 复制代码
// 初始化 SolongWallet 适配器
const solongAdapter = new SolongWalletAdapter();

// 组合多个钱包适配器
const wallets = useMemo(
    () => [
        new PhantomWalletAdapter(),
        new SolongWalletAdapter(),
        // 可以添加更多适配器...
    ],
    []
);

// 提供钱包适配器给应用
<WalletProvider wallets={wallets} autoConnect>
    {/* 应用组件 */}
</WalletProvider>

4.2.3钱包连接和状态管理

javascript 复制代码
<ConnectionProvider endpoint={endpoint}>
    <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
            {/* 应用组件 */}
        </WalletModalProvider>
    </WalletProvider>
</ConnectionProvider>

<div style={styles.walletButtons}>
    <WalletMultiButton />
    <WalletDisconnectButton />
</div>

4.2.4 交易操作

javascript 复制代码
// 在组件内部获取钱包连接和功能
const { connection } = useConnection();
const { publicKey, sendTransaction } = useWallet();

// 创建交易
const transaction = new Transaction();
const recipientPubKey = Keypair.generate().publicKey;

// 添加转账指令
transaction.add(
    SystemProgram.transfer({
        fromPubkey: publicKey,
        toPubkey: recipientPubKey,
        lamports: 0.01 * LAMPORTS_PER_SOL,
    })
);

// 获取最新区块哈希
const { blockhash, lastValidBlockHeight } = value;
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;

// 发送交易
const signature = await sendTransaction(transaction, connection, { 
    minContextSlot,
    skipPreflight: false 
});

// 等待确认
const confirmationResponse = await connection.confirmTransaction({
    blockhash,
    lastValidBlockHeight,
    signature,
}, 'confirmed');

4.2.5 RPC 配置和管理

javascript 复制代码
export const RPC_CONFIG = {
    // 默认 Solana Devnet - 有低速率限制
    DEFAULT: clusterApiUrl(WalletAdapterNetwork.Devnet),
    
    // 替代端点 - 在这里添加您的 API 密钥
    HELIUS: 'https://rpc-devnet.helius.xyz/your-api-key',
    QUICKNODE: 'https://your-quicknode-devnet-endpoint',
    ALCHEMY: 'https://solana-devnet.g.alchemy.com/v2/your-api-key',
    
    // 默认使用哪个端点
    ACTIVE: 'DEFAULT',
    
    // 速率限制错误的最大重试次数
    MAX_RETRIES: 3,
    
    // 指数退避的基本延迟(毫秒)
    BASE_DELAY: 1000,
    
    // 余额轮询间隔(毫秒)- 增加到 30 秒
    POLLING_INTERVAL: 30000,
};
相关推荐
地图工程师5 天前
Nacos + Dubbo3 实现微服务的Rpc调用
spring cloud·rpc·dubbo3
极客Kimi5 天前
Dubbo RPC 原理
网络协议·rpc·dubbo
代码洁癖症患者5 天前
玩转 Netty : 如何设计高性能RPC通信组件
网络·网络协议·rpc
红豆和绿豆6 天前
如何实现将http请求转化为rpc请求
网络协议·http·rpc
mit6.8246 天前
[实现Rpc] 客户端 | Requestor | RpcCaller的设计实现
c++·rpc
+7208 天前
如何在java中用httpclient实现rpc get请求
java·qt·rpc
C语言扫地僧8 天前
RPC 框架项目剖析
c++·网络协议·学习·rpc
+7208 天前
如何使用HttpClinet实现RPC返回对象类型
网络·网络协议·rpc
LUCIAZZZ8 天前
Https解决了Http的哪些问题
java·网络·网络协议·spring·http·rpc·https