Derick
1139 words
6 minutes
深入理解Solana账户与交易机制

一、为什么 Solana 的账户模型如此特别?#

Solana 与 EVM 的最大不同,是账户不仅是资产容器,还是数据存储单元

它更像是一种“文件系统模型”,每个账户都是一个独立的文件:

  • Program Account —— 类似可执行文件(智能合约逻辑)。
  • Data Account —— 存储数据的账户,由特定程序控制读写权限。
  • System Account —— 系统级账户,用于创建新账户或转账 SOL。

在 Solana 上,一笔交易的执行过程更像是:

“程序被加载进多个账户的上下文中,然后对其中的账户进行读写操作。”


二、账户的基本结构#

每个账户在链上的核心字段如下:

字段含义
lamports账户余额,单位为 lamports(1 SOL = 1e9 lamports)
owner该账户由哪个 Program 拥有(例如 SystemProgram
data原始二进制数据,由程序自定义结构
executable是否是可执行账户(即 Program)
rentEpoch租金周期,用于回收长期闲置账户

你可以理解为:

“每个账户既能存钱,又能存数据,还能指定由谁来控制它。”


三、交易的三层结构:Transaction → Message → Instruction#

Solana 的交易不是单条指令,而是一组“批处理操作”。

它包含多个指令(Instruction),每条指令由一个 Program 执行。

1️⃣ Transaction#

最外层结构,包含签名、公钥集合和消息。

2️⃣ Message#

打包了一系列要执行的指令(Instructions),以及这些指令涉及的账户。

3️⃣ Instruction#

单个操作,由:

  • Program ID(哪个程序执行)
  • Accounts(涉及哪些账户)
  • Data(操作参数)

整体结构如下:

Transaction
 └── Message
      ├── AccountKeys
      ├── RecentBlockhash
      └── Instructions[]
             ├── ProgramID
             ├── AccountIndices[]
             └── Data[]

四、Solana 的签名机制#

Solana 使用 Ed25519 签名算法。

每笔交易必须由至少一个签名者授权(通常是付款方的账户私钥)。

签名的目标数据是 Message 的哈希,而不是交易体。

这样做的好处是可快速验证交易签名的正确性,且支持批量签名验证。

简单来说:签名的是 Message,广播的是 Transaction。


五、构造一笔转账交易(Go 实战)#

现在我们通过 Go SDK 来构造并发送一笔简单的 SOL 转账。

导入依赖#

import (
	"context"
	"fmt"
	"log"

	"github.com/gagliardetto/solana-go"
	"github.com/gagliardetto/solana-go/rpc"
	"github.com/gagliardetto/solana-go/rpc/jsonrpc"
	"github.com/gagliardetto/solana-go/text"
)

构建核心逻辑#

func main() {
	ctx := context.Background()
	client := rpc.New(rpc.DevNet_RPC)

	// 1️⃣ 加载本地私钥(从 solana-keygen 生成的钱包)
	sender, err := solana.PrivateKeyFromSolanaKeygenFile("/Users/alan/.config/solana/devnet.json")
	if err != nil {
		log.Fatalf("加载钱包失败: %v", err)
	}

	receiver := solana.MustPublicKeyFromBase58("接收者钱包地址")

	// 2️⃣ 构造转账指令
	instruction := solana.NewInstruction(
		solana.SystemProgramID,
		solana.MustToAccountMeta(sender.PublicKey(), true, true),
		solana.MustToAccountMeta(receiver, false, true),
	).SetData(
		solana.MustEncodeSystemTransfer(
			solana.NewSystemTransferInstruction(
				sender.PublicKey(),
				receiver,
				1_000_000_000, // 转账 1 SOL = 1e9 lamports
			),
		),
	)

	// 3️⃣ 获取最新区块哈希
	recent, err := client.GetRecentBlockhash(ctx, rpc.CommitmentFinalized)
	if err != nil {
		log.Fatalf("获取区块哈希失败: %v", err)
	}

	// 4️⃣ 构造交易消息
	tx, err := solana.NewTransaction(
		[]solana.Instruction{instruction},
		recent.Value.Blockhash,
		sender.PublicKey(),
	)
	if err != nil {
		log.Fatalf("创建交易失败: %v", err)
	}

	// 5️⃣ 签名交易
	_, err = tx.Sign(func(key solana.PublicKey) *solana.PrivateKey {
		if sender.PublicKey().Equals(key) {
			return &sender
		}
		return nil
	})
	if err != nil {
		log.Fatalf("签名失败: %v", err)
	}

	// 6️⃣ 广播交易
	sig, err := client.SendTransaction(ctx, tx)
	if err != nil {
		log.Fatalf("广播失败: %v", err)
	}

	fmt.Println("✅ 交易已提交,签名哈希:", sig)
}

六、用 Go 工具查看交易结构#

SDK 提供了一个非常有用的调试工具 text.NewEncoder()

encoder := text.NewEncoder(os.Stdout)
encoder.Encode(tx.Message)

输出结构大致如下:

Message {
  recent_blockhash: 7dMjeDkBmw6axbiTzA8npPQfLszDQAJhz3fWQ4XgG9b5
  account_keys: [
    1. Sender
    2. Receiver
    3. SystemProgram
  ]
  instructions: [
    0: Program(SystemProgram) -> Transfer 1 SOL
  ]
}

这能帮助我们理解交易内部的账户引用关系,非常适合调试复杂合约调用。


七、RPC 与 gRPC 接口的使用#

Solana 节点支持两种交互方式:

模式协议适合场景
JSON-RPCHTTP(S)简单查询与交易提交
gRPCBinary over HTTP/2高并发、低延迟的链上同步与监听

在 Go SDK 中:

  • rpc.New() → JSON-RPC 客户端
  • jsonrpc.NewClient() → gRPC 模式客户端

例如,我们可以通过 gRPC 订阅区块事件:

grpcClient := jsonrpc.NewClient("https://api.devnet.solana.com:443")
stream, err := grpcClient.SubscribeSlotUpdates(ctx)
if err != nil {
	log.Fatalf("订阅失败: %v", err)
}

for {
	slotUpdate, err := stream.Recv()
	if err != nil {
		log.Fatalf("接收错误: %v", err)
	}
	fmt.Printf("新区块 Slot: %v\n", slotUpdate.Slot)
}

这种方式非常适合写区块监听器、价格同步服务等需要实时响应的业务。


八、小结#

模块内容
账户模型通用账户体系、数据可存储与执行控制
交易结构Transaction → Message → Instruction
签名机制Ed25519,对 Message 哈希签名
Go 实战构造与发送转账交易
通信接口JSON-RPC + gRPC 双模式支持
深入理解Solana账户与交易机制
https://blog.ithuo.net/posts/solana-accounts-and-transactions/
Author
Derick
Published at
2024-12-12