长安链 SDK-Go:从跑通到用对
业务应用 不直接 和链打交道:交易构造与签名、gRPC 长连接、TLS、结果确认、订阅流——都由 SDK 收敛成 ChainClient 上的方法调用。跑通一个程序只是起点,用对身份、分清响应、处理持续数据流,才是业务接入的完整路径。
阅读基线
原始素材为 60 分钟、演示驱动 的技术分享。代码基线:sdk-go@v2.4.1_qc;教程仓库:sdk-go-demo。
文中代码均摘自真实可运行文件,保留原稿标注的路径与行号;带 ... 的片段表示省略,完整程序见对应文件。本文完整保留原稿章节、演示、配置及接口索引,仅调整展示形式。
1. SDK 是什么
业务应用 不直接 和链打交道:交易构造与签名、gRPC 长连接、TLS、结果确认、订阅流——都由 SDK 收敛成 ChainClient 上的方法调用。
flowchart LR
subgraph APP["业务应用层(开发者侧)"]
direction TB
A1["存证 / 溯源业务"]
A2["链上索引器 / 数据管道"]
A3["实时监控 / 告警 / 风控"]
end
subgraph SDK["chainmaker-sdk-go —— Go 业务 API 入口"]
direction TB
S0["ChainClient"]
S1["连接池 + 多节点择优 + 重试"]
S2["交易构造 / 私钥签名 / TLS"]
S3["合约调用与查询"]
S4["订阅服务(block / tx / event)"]
S5["链配置 · 证书 · 多签 · Gas · 归档 · 隐私计算 ..."]
end
subgraph CHAIN["长安链 ChainMaker"]
direction TB
N1["节点1 RPC :12301"]
N2["节点2 RPC :12302"]
N3["节点N RPC"]
LEDGER["账本 + 合约虚拟机<br/>WASM / EVM / 系统合约"]
end
A1 --> S0
A2 --> S0
A3 --> S0
S0 --> S1
S0 --> S2
S0 --> S3
S0 --> S4
S0 --> S5
S1 -- "gRPC(TLS)" --> N1
S1 -- "gRPC(TLS)" --> N2
S1 -- "gRPC(TLS)" --> N3
N1 --> LEDGER
N2 --> LEDGER
N3 --> LEDGER
S3 -. "同步调用/查询" .-> N1
S4 -. "gRPC 流式推送" .-> N2 一句话: chainmaker-sdk-go 是 Go 业务接入长安链的 API 封装与协议适配层。
2. Quickstart:5 分钟跑通第一个程序
要准备什么
| 要准备 | 从哪来 | 怎么放 |
|---|---|---|
Go 工程 go.mod | go mod init + go get chainmaker.org/chainmaker/sdk-go/v2 | 项目根目录 |
SDK 配置 sdk_config.yml | 抄 sdk-go-demo/testdata/configs/(6 套模板) | testdata/configs/ |
| 证书/密钥 | 从链部署目录 crypto-config/ 复制 | 配置里写相对路径, 以运行目录为基准 |
| 合约文件 | 官方标准合约(存证 wasm / EVM bin+abi) | testdata/contracts/ |
证书目录结构:每个目录是什么
testdata/configs/ 下两个证书根目录,对应两种身份体系:
testdata/configs/
├── crypto-config/ # cert 模式(证书身份)——本演示使用
│ ├── std/ # 标准密码套件(SHA256/ECDSA-RSA)
│ └── gm/ # 国密套件(SM2/SM3,GMTLS 双证书)
├── crypto-config-pk/ # pk 模式(公钥身份)
│ ├── std/ # 标准套件
│ ├── gm/ # 国密套件
│ └── k1/ # secp256k1 套件(以太坊式曲线,配 EVM 地址)
└── sdk_config*.yml # 6 套配置 = 3 种认证模式 × TLS 开/关
cert 模式按“组织”分目录(crypto-config/std/ 下,以 wx-org1 为例,全部真实文件):
crypto-config/std/wx-org1.chainmaker.org/
├── ca/ # 组织 CA —— SDK 配置的 trust_root_paths 指向这里
│ ├── ca.crt # 校验节点 TLS 证书用
│ └── ca.key # (签发用,正常不随应用分发)
├── node/ # 节点身份(部署链用;客户端一般只读它的 CA)
│ ├── common1/ # 同步/普通节点:sign.* 签名 + tls.* 通信 + nodeid
│ └── consensus1/ # 共识节点:同构
└── user/ # 用户身份 —— SDK 客户端在这里取自己的证书
├── admin1/ # 管理员:治理类交易背书用(部署合约收的就是 admin1 的签名)
├── client1/ # 普通客户端:tls.*(连接) + sign.*(交易签名) + addr(账户地址)
│ # 以及 sign.key.enc(加密私钥样例,配 *_pwd 使用)
└── light1/ # 轻节点用户(06-cert-alias 演示“别名换绑证书”时用到它)
pk 模式按“节点”分目录(crypto-config-pk/std/,没有身份签名证书,身份 = 公钥):
crypto-config-pk/std/node1/
├── node1.key / node1.pem # 节点公私钥(.pem 是公钥,无 .crt)
├── node1.tls.crt / node1.tls.key # TLS 通信证书(只管连接,不代表身份)
├── admin/admin1..admin16/ # 每个管理员一组 .key + .pem
├── user/ # 普通用户公私钥
├── client-tls/client1/ # TLS 客户端证书
└── ca/wx-org1..16/ # 多组织 CA(TLS 校验用)
三种模式的区别与演示选择
| cert(permissionedWithCert) | pk(public) | pwk(permissionedWithKey) | |
|---|---|---|---|
| 身份载体 | 证书(sign.crt) | 公钥(.pem),无证书 | 公钥 + 链上权限管理 |
| 目录组织 | 按 组织(wx-orgN) | 按 节点(nodeN) | 复用 cert 布局 |
| 签名材料 | sign.key + sign.crt | .key + .pem | .key |
| 目录来源 | 链部署 crypto-config/ | 部署工具生成的公钥集 | 同 pk |
| 对应配置 | sdk_config(_tls).yml | sdk_config_pk(_tls).yml | sdk_config_pwk(_tls).yml |
本演示的身份与密码套件
本演示全部使用 crypto-config/std/(cert 模式 + 标准密码套件):sdk_config.yml 引用 wx-org1.../user/client1/ 做业务调用,部署合约时由 pkg/util.AdminEndorsers 收集四个组织的 admin1 背书。
国密链把路径里的 std 换成 gm 即可,另需启用 GMTLS 双证书(user_enc_* 配置)。
已核实:sdk_config_pwk.yml 引用的 wx-org1.../admin/admin.key 在当前 testdata 中 不存在(该组织下是 user/admin1/),pwk 模板无法直接跑通——演示时只讲差异,不现场运行 pwk。
真实演示环境:sdk-go-demo 仓库
原分享使用 sdk-go-demo 作为递进式教程仓库;订阅优化演示使用 SDK 仓库的 examples/subscribe/optimize。教程仓库的结构如下,准备好对应链环境与配置后运行:
sdk-go-demo/
├── 01-quickstart .. 17-evm/ # 17 个递进教程(本讲用 01/06/07/08/15)
├── 99-probe/ # 连不上链时的只读诊断探针
├── pkg/util/util.go # AdminEndorsers / MustSuccess 等公共辅助
├── testdata/
│ ├── configs/ # 6 套 SDK 配置 + 上面两棵证书树
│ └── contracts/ # 标准合约,开箱即用
│ ├── wasm/evidence/ # 存证(Rust WASM,含源码 src/fact.rs)
│ ├── evm/erc20|erc721/ # EVM(.bin + .abi + .sol 源码)
│ ├── wasm/bulletproofs/ # 零知识范围证明
│ └── wasm/paillier/ # 同态加密
└── Makefile # make run-01 ~ run-17 一键运行
一键命令(Makefile 已封装):
make run-01 # 运行 01-quickstart(01~17 序号均可)
make run DEMO=07-subscribe
make check # build + vet + fmt 一键检查(贡献 demo 前跑)
连不上链先跑探针(99-probe,只读不改链):打印链的 auth_type/crypto.hash、各组织 trust_root 证书指纹、共识组织、CONTRACT_MANAGE 背书策略——逐项与本地 sdk_config.yml 对比,CA 不匹配 / auth_type 不一致一眼可见。
原分享演示与教程对照:
| 演示 | 目录 | 讲到 |
|---|---|---|
| 演示 1 | 01-quickstart | §2 Quickstart |
| 演示 2 | 07-subscribe | §6 订阅 |
| 演示 3 | examples/subscribe/optimize(sdk-go 仓库) | §7 订阅优化 |
| 演示 4 | 08-archive | §8 归档 |
| 引用 | 06-cert-alias / 03-block-query / 15-transaction | §3 基本功能 |
演示 1:Quickstart
预期输出:
第一个程序长什么样
| sdk-go-demo/01-quickstart/main.go · 原稿行号 16–30 | |
|---|---|
记住三件事:
- 配置文件一把梭:链、节点、身份、TLS 全在
sdk_config.yml。 client复用,Stop收尾。- 连接谁、以谁的身份 → 配置决定;接下来只关心“调用哪个合约、传什么参数”。
最容易踩的四个坑
连接前先核对这四项
- 相对路径以 运行目录 为基准:
cd 01-quickstart里跑就用../testdata/...。 trust_root_paths指向 节点 CA:连别人的链必须换对方 CA。tls_host_name与节点证书 SAN 一致(如chainmaker.org)。auth_type必须与目标链一致:public=pk,permissionedWithKey=pwk。
全部配置项速查 → 见文末 附录 A。
3. 基本功能:一步到位的方法
核心认知:大多数场景不需要手动构造 Payload。
两类返回
第一类:返回 TxResponse(写入类及部分查询接口,要检查状态码)。
// 01-quickstart/main.go:69 —— 同步等执行结果
invokeResp, err := client.InvokeContract(claimContract, "save", "", kvs, -1, true)
// 01-quickstart/main.go:85 —— 只读查询
queryResp, err := client.QueryContract(claimContract, "find_by_file_hash", queryKvs, -1)
| sdk-go-demo/06-cert-alias/main.go · 原稿行号 97–104 | |
|---|---|
第二类:直接返回解包好的结构体(查询类,拿到就能用)。
// 03-block-query/main.go:22
height, err := client.GetCurrentBlockHeight() // uint64
// 03-block-query/main.go:31
blockInfo, err := client.GetBlockByHeight(height-1, false) // *common.BlockInfo
// 03-block-query/main.go:67
chainInfo, err := client.GetChainInfo() // *discovery.ChainInfo,含节点列表
第二类连两层状态码都替你处理了,失败直接体现在 err;第一类要自己检查。
真实例子:存证写入 + 查询
kvs := []*common.KeyValuePair{
{Key: "time", Value: []byte(curTime)},
{Key: "file_hash", Value: []byte(fileHash)},
{Key: "file_name", Value: []byte(fmt.Sprintf("file_%s", curTime))},
}
invokeResp, err := client.InvokeContract(claimContract, "save", "", kvs, -1, true)
...
queryResp, err := client.QueryContract(claimContract, "find_by_file_hash", queryKvs, -1)
fmt.Printf("query contract success: result=%s\n", string(queryResp.ContractResult.Result))
- 参数是
[]*common.KeyValuePair:string键 +[]byte值, 名字和编码按合约约定。 - 检查顺序:
err→resp.Code == SUCCESS→ContractResult.Code == 0→ 解析Result。 ContractResult.Result是[]byte:本例string(...)打印;JSON 就json.Unmarshal,协议由合约说了算。
什么时候够用
判断标准:这个操作只需你一个人的签名。 业务调用、只读查询、证书别名、Gas 查询——都够用。
证书别名:不要重复 AddAlias
一个真实的坑(06-cert-alias/main.go:85-89 注释):配置了 alias 时 NewChainClient 自动把别名上链,此后 sender 变为 ALIAS 类型, 再手动调 AddAlias() 会被链端拒绝。
4. 复杂场景:多方签名
触发条件:链的权限策略要求多个身份对同一操作签名——部署/升级/冻结合约、改链配置。
三步模式(真实部署代码)
一句话分工:
CreateContractCreatePayload描述“要做什么”,不发送。AdminEndorsers各背书方 对同一份Payload分别签名(改一个字节全部重签)。SendContractManageRequest补上发起者签名并发送。
AdminEndorsers 不是 SDK 接口,是 demo 的辅助函数(sdk-go-demo/pkg/util/util.go:31)——演示环境把 4 个组织 admin 私钥都放本地的便利写法。生产环境私钥分散,应各自签名后收集,或走多签系统合约。
查表速判
| 场景 | 模式 | 代表接口 |
|---|---|---|
| 业务调用、查询、别名 | 一步到位 | InvokeContract / QueryContract / AddAlias |
| 部署/升级/冻结合约 | Payload + 背书 + Send | CreateContractCreatePayload + SendContractManageRequest |
| 链配置更新 | Payload + 背书 + Send | CreateChainConfig*Payload + SendChainConfigUpdateRequest |
| 自己控制请求结构 | 显式两步 | GetTxRequest(...) → SendTxRequest(...) |
5. 底层:一次请求的完整流程
前面两种模式,底层共用同一条流水线。
flowchart LR
subgraph APP["调用方"]
direction TB
K["1. 准备参数<br/>合约 · 方法<br/>kvs 参数列表"]
C["5. 检查返回<br/>err / resp<br/>两层状态码"]
D["6. 解析结果<br/>按协议解码<br/>校验业务字段"]
C --> D
end
subgraph SDK["chainmaker-sdk-go"]
direction TB
P["2. 构造 Payload<br/>链ID · 请求类型<br/>合约 · 方法 · 参数"]
R["3. 组装并签名<br/>TxRequest<br/>载荷 + 发起者签名"]
S["4. 发送请求<br/>SendTxRequest<br/>timeout · withSyncResult"]
T["返回 TxResponse<br/>外层状态 · TxId<br/>ContractResult"]
P -- "GenerateTxRequest" --> R
R -- "已签名请求" --> S
S -. "发送调用返回" .-> T
end
subgraph REMOTE["RPC 调用边界"]
direction TB
RPC["RPC 接口<br/>请求发出<br/>响应返回"]
end
K -- "传入参数" --> P
S -- "gRPC 发送 TxRequest" --> RPC
RPC -. "gRPC 返回 TxResponse" .-> T
T -. "返回 resp / err" .-> C
classDef box fill:#ece8ff,stroke:#a78bfa,color:#333333
class K,C,D,P,R,S,T,RPC box
linkStyle 1,2,4,5 stroke:#dc2626
linkStyle 3,6,7 stroke:#2563eb 读图:红实线向右 = 请求发出;蓝虚线向左 = 响应返回。InvokeContract 内部就是 2→3→4。
请求怎么组装
| 层 | 结构 | 关键字段 |
|---|---|---|
| 参数 | KeyValuePair 列表 | Key: string / Value: bytes,放入 Payload.Parameters |
| 载荷 | Payload | ChainId / TxType / ContractName / Method / TxId / Timestamp |
| 请求 | TxRequest | Payload + Sender(发起者签名)+ 按需 Endorsers / Payer |
边界:签名后改 Payload 必须重新签名;构造完成 ≠ 已发送。
响应怎么检查(四步,不跳步)
| 层级 | 字段 | 说明 |
|---|---|---|
| ① Go 返回值 | err | 构造/签名/通信/等待阶段的错误 |
| ② 外层 | resp.Code / Message | 交易状态码,对照 TxStatusCode_SUCCESS |
| ② 外层 | TxId / TxBlockHeight | 跟踪标识与元数据; 有 TxId ≠ 已上链 |
| ③ 合约层 | ContractResult.Code | 0 才是合约执行成功,与外层不是一回事 |
| ④ 数据 | ContractResult.Result | 原始 []byte,按协议解码 |
异步提交成功不等于写入成功
异步提交的坑:withSyncResult=false 时拿到的是提交响应,Code=SUCCESS 不能 作为写入成功的依据——保留 TxId,用 GetTxByTxId 或订阅确认最终结果。
6. 订阅:从一次响应到持续数据流
轮询要反复调 GetBlockByHeight 并自己维护游标;订阅由节点在数据产生时 主动推送。
演示 2:区块、交易与合约事件三路订阅
三路订阅同时滚动输出(跑 30 秒自动退出):
订阅接口与返回类型
| 接口 | 通道元素类型 | 关键参数 |
|---|---|---|
SubscribeBlock(ctx, start, end, withRWSet, onlyHeader) | *BlockHeader 或 *BlockInfo | onlyHeader=true 时忽略 withRWSet |
SubscribeTx(ctx, start, end, contractName, txIds) | *Transaction | 空合约名=全部 |
SubscribeContractEvent(ctx, start, end, name, topic) | *ContractEventInfo | 单 topic |
SubscribeContractEvents(ctx, start, end, name, topics []string) | *ContractEventInfo | 多 topic(v2.4.1 新增) |
高度语义速查
| start / end | 含义 |
|---|---|
-1, -1 | 实时订阅最新 |
0, -1 | 从头补历史,再持续实时 |
0, 10 | 补完区间即结束(channel 关闭) |
| 起始 > 当前高度 / 起始 > 终止 / < -1 | 报错 |
生命周期:ctx 取消或 client.Stop() → 退出收流;channel 关闭后 ok=false 必须处理,否则死循环读零值。
7. 订阅优化:多节点自动择优 + 断点续订
解决三个真实痛点
- 连到落后节点:连接池里多个节点,可能正好连着慢的。
- 断流丢数据:连接抖动 / EOF 后要 从已收到的位置续订,不是从头再来。
- 消费端太慢:通道缓冲 256,堆积有风险。
机制
flowchart LR
START["SubscribeBlockWithOptimize<br/>SubscribeContractEvent(s)WithOptimize"] --> CHK{"config.optimizeDetection > 0<br/>且 nodeList > 1 ?"}
CHK -- 否 --> PLAIN["降级为普通订阅<br/>(事件订阅直接报错返回)"]
CHK -- 是 --> SUB["actualSubscribe()<br/>建立 gRPC 流 + 收流协程"]
SUB --> TICK["定时器 optimizeDetection 秒"]
TICK --> IDLE{"距上次收到数据<br/>超过 switchTimeDiff 秒 ?"}
IDLE -- 否 --> TICK
IDLE -- 是 --> PROBE["getLastBlockHeight()<br/>用当前最优连接探高度"]
PROBE --> DIFF{"最优高度 - 已推送高度 > 0 ?"}
DIFF -- 否 --> TICK
DIFF -- 是 --> NEWREQ["switchHandler.NewSubscribeTxReq()<br/>以 pushedBlockHeight 为起点重建请求"]
NEWREQ --> NIL{"返回 nil ?<br/>(已到 endBlock)"}
NIL -- 是 --> EXIT["正常退出,关闭 channel"]
NIL -- 否 --> CANCEL["curCancel() 取消旧订阅"]
CANCEL --> SUB
SUB -. "收到 error 连续 >= 10 次" .-> EXIT 关键结论:会不会自动升级?分类型
区块订阅会,事件订阅不会:
SubscribeContractEvents 的注释明确写着“ 不会自动启用优化模式 ”(sdk_subscribe.go:203)——事件订阅必须显式调 SubscribeContractEvent(s)WithOptimize。
参数与配置
| 参数 / 配置 | 语义 | 默认 |
|---|---|---|
optimizeDetection(接口参数) | 检测周期(秒) | <=0 取 15s |
switchTimeDiff(接口参数) | 静默多久才探测切换(秒) | <=0 取 10s |
optimize_detection(配置) | 连接择优周期; 仅多节点生效 | 60s;关闭设 -1 |
disable_subscribe_optimize(配置) | 关闭区块订阅自动升级 | false |
版本要求:优化订阅自 v2.3.7;合约事件优化要求底链 ≥ v2.3.6。
演示 3:多节点环境下的优化订阅
观察:30s 超时自动退出;事件返回 ContractEventInfoList;停掉一个节点可看到日志:
Subscriber switching connection conditions are met → restart subscription success
两个必讲的坑
返回类型与降级策略都不一样
- 普通事件订阅返回
*ContractEventInfo( 单个,SDK 拆开逐个推);优化版返回*ContractEventInfoList——断言类型不同,套错会 panic;且ContractEvents可能为空,直接[0]越界。 - 单节点或未配
optimize_detection时,事件订阅优化 直接报错不降级;区块订阅则降级为普通订阅。
8. 归档:链上瘦身与链外查询
一句话:归档把旧区块搬到链外存储,节点存储有界;归档数据仍可查、可恢复。
数据去哪由配置决定(archive: 段):mysql(自建库)或 archivecenter(归档中心,配合 archive_center_query_first 让查询优先走链外)。
四个操作(摘自 08-archive/main.go,完整程序可运行)
// 08-archive/main.go:111 —— 查节点归档状态
status, err := client.GetArchiveStatus()
// 08-archive/main.go:130 —— 当前可归档高度
height, err := client.GetArchivedBlockHeight()
// 08-archive/main.go:139 —— 归档到该高度,回调逐块上报进度
err = client.ArchiveBlocks(height, "quick", func(msg sdk.ProcessMessage) error {
fmt.Printf("archive progress: %+v\n", msg)
return nil
})
// 08-archive/main.go:151 —— 恢复归档区块回节点
err = client.RestoreBlocks(1, "quick", func(msg sdk.ProcessMessage) error { ... })
ArchiveBlocks 内部自动做:查状态 → 算起止高度 → 归档服务未注册时用创世块注册 → 逐块搬运。
第二个参数 mode 是 保留参数,当前未使用——传什么都没语义。
归档后查询 + 三个坑
归档后的区块 不能 再用 GetBlockByHeight,改用 GetArchivedBlockByTxId / GetArchivedBlockByHash / GetArchivedBlockByHeight / GetArchivedTxByTxId。
归档任务不要并发跑
- 高度截断:超过
MaxAllowArchiveHeight的部分直接截掉。 - 不允许跳块:节点与归档服务高度不连续报
not match。 - 串行调度:任一方 in process 时再次发起直接报错——归档任务别并发跑。
9. 版本时间线:2.3.7 → 2.4.1 用户可感知变更
v2.3.7:订阅体验升级
- 优化订阅区块:
SubscribeBlockWithOptimize,多节点自动择优 + 断点续订。 - 优化订阅合约事件:
SubscribeContractEventWithOptimize(底链需 ≥ v2.3.6)。 - 新增配置项:
optimize_detection(连接择优周期)、node_only_async(老链兼容)。
v2.3.8:多签升级
- 多签 V2 方法族:
MultiSignContractReq/Vote/TrigV2 系列 + Payer / GasLimit 变体。 - 区块高度查询优化:
GetCurrentBlockHeight走新接口,低版本底链自动回退。
v2.3.12:运维信息增强
- 查节点上所有链:
GetChainMakerServerMessage。 - 查服务端完整响应:
GetChainMakerServerInfo。
v2.4.1:治理与可观测
- 合约 Owner 转移:
CreateContractTransferOwnerPayload(SDK 侧入参预校验)。 - 查询合约字节码:
GetContractBytecode。 - 资源白名单:增/删/改/查 4 个接口。
- 账户序列号:
GetAccountSequence/GetCurrentAccountSequence。 - 多 topic 事件订阅:
SubscribeContractEvents(+WithOptimize),单 topic 版保留为兼容壳。
明细与证据表见原分享内部大纲 §8;正式发布口径另需确认1。
10. 总结
- 五分钟搭好工程(配置 + 证书 + 合约四件套)就能跑通第一个程序。
- 日常调用用一步到位的方法;多方签名才升级到
Payload+ 背书 + 发送。 - 底层流程 KV →
Payload→ 签名 Request → 发送 → 状态检查 → 业务解码,解释了便捷方法做了什么。 - 订阅 把一次响应扩展成持续数据流; 优化订阅 再加节点探测与切换续订。
- 归档 让链上存储有界:先查状态再搬运、串行调度、归档后改用
GetArchived*。
学习路径
入门:01-quickstart(5m) → 02-contract-lifecycle(15m) → 03-block-query(10m)
核心:04-chain-config → 05-cert → 06-cert-alias → 07-subscribe(10m)
进阶:08-archive → 09-multisign → 10-gas → 11-payer → 12-pubkey → 13-tx-pool → 14-consensus-sync → 15-transaction
专题:16-privacy → 17-evm
两套代码资产:
sdk-go-demo:01→17 递进式学习路径。sdk-go/examples:按接口分类的 API 参考,本文演示 3 出自这里,其余演示出自教程仓库。
附录 A:SDK 配置项速查
依据 sdk-go/utils/config.go 配置模型与 testdata/configs/ 6 套真实模板核对。
配置文件全览(cert + TLS 模板骨架)
完整 sdk_config.yml 骨架:点击可折叠
pk 模式差异:无 org_id、无签名证书,显式 auth_type: public 与 crypto.hash;证书路径从 crypto-config-pk/ 取。 pwk 同理,auth_type: permissionedWithKey。
一句话分清两组证书:
- TLS 证书
- 管“连得上”。
- 签名证书
- 管“交易算谁发的”。
附录 B:SDKInterface 接口索引
依据 sdk-go/sdk_interface.go:63-111:SDKInterface 采用 接口组合设计——按需依赖特定功能、Mock 测试时可只实现所需接口。ChainClient 实现全部 16 个子接口,方法都以 client.Xxx(...) 直接调用。
| 子接口 | 职责 | 代表方法(节选) | 定义位置 | 对应教程 |
|---|---|---|---|---|
ChainClientBasic | 生命周期与版本 | Stop、GetChainMakerServerVersion、GetChainMakerServerMessage/Info | :303 | 01 · 99-probe |
ContractManager | 合约全生命周期 | CreateContractCreate/Upgrade/Freeze/Unfreeze/RevokePayload、TransferOwnerPayload、InvokeContract、QueryContract、GetTxRequest、SendTxRequest | :565 | 01 · 02 · 17 |
BlockQuery | 区块/交易查询 | GetTxByTxId、GetBlockByHeight/ByHash/ByTxId、GetLastBlock、GetChainInfo | :871 | 01 · 03 |
ChainConfigManager | 链配置 | GetChainConfig、GetChainConfigSequence、CreateChainConfig*Payload、SendChainConfigUpdateRequest | :392 | 04 |
CertManager | 证书管理 | AddCert、DeleteCert、QueryCert、GetCertHash、SendCertManageRequest | :338 | 05 |
CertAliasManager | 证书别名 | AddAlias、QueryCertsAlias、UpdateCertByAlias、DeleteCertsAlias | :213 | 06 |
SubscribeService | 订阅 | SubscribeBlock/Tx/ContractEvent(s)、ByPreAlias/ByPreTxId/ByPreOrgId、*WithOptimize、SubscribeWithTxReq | :966 | 07(§6–§7) |
ArchiveManager | 数据归档 | GetArchiveStatus、ArchiveBlocks、RestoreBlocks、GetArchivedBlockBy*、GetArchivedTxByTxId | :254 | 08(§8) |
MultiSignManager | 多签 | MultiSignContractReq/Vote/Trig/Query(+V2、+Payer、+GasLimit 变体) | :743 | 09 |
GasManager | Gas 管理 | GetGasAdmin、GetGasBalance、EstimateGas、AttachGasLimit、CreateRechargeGasPayload、FrozenGasAccountPayload | :646 | 10 |
PayerManager | Gas 代付 | SetContractMethodPayer、UnsetContractMethodPayer、QueryContractMethodPayer、QueryTxPayer | :821 | 11 |
PubkeyManager | 公钥身份 | CreatePubkeyAdd/Del/QueryPayload、SendPubkeyManageRequest | :842 | 12 |
TxPoolManager | 交易池 | GetPoolStatus、GetTxIdsByTypeAndStage、GetTxsInPoolByTxIds | :1025 | 13 |
ConsensusSyncManager | 共识与同步 | GetConsensusValidators、GetConsensusHeight、GetSyncState、同步规则系列 | :525 | 14 |
TransactionManager | 交易治理 | CreateTxBlacklistAdd/DeletePayload、GetTxBlacklist、SendTransactionManagerRequest | :1044 | 15 |
HibeService | 层级属性加密 | CreateHibeTxPayloadParamsWithHibeParams、QueryHibeParamsWithOrgId、DecryptHibeTxByTxId | :707 | examples/hibe |
找接口的路径:SDKInterface 组合(sdk_interface.go:63)→ 子接口定义与完整方法签名 → sdk-go/examples/<模块>/main.go 抄可运行片段。EVM 无独立接口:通过 RuntimeType_EVM + GetEVMAddressFrom* 工具函数体现。
最后更新:2026-10-09
-
原稿基线说明:v2.4.1 无 tag 仅分支,正式发布口径以 Release owner 确认为准。此处记录的是原分享基线,不代表后续发布状态。 ↩