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-RPC | HTTP(S) | 简单查询与交易提交 |
| gRPC | Binary 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 双模式支持 |
Share
If this article helped you, please share it with others!
深入理解Solana账户与交易机制
https://blog.ithuo.net/posts/solana-accounts-and-transactions/ Last updated on 2024-12-12,410 days ago
Some content may be outdated