主题
03 · 交易跨包全链路
当前银行侧主链路是 Facade → Wallet Node → Endorser → Auditor → Fabric-X。旧文档中的 app/institution 与 InstitutionOpsService 已分别改为 app/walletnode 与 WalletNodeOpsService。
Transfer 总览
1. Facade 认证与路由
除公开方法外,Facade 要求 x-key-id、x-timestamp、x-signature。中间件从 BizHub 同步到内存的认证资料中查找 Ed25519 公钥,对规范化请求进行验签,并把机构身份写入 context。
Wallet-bound 请求不由客户端选择节点。Facade 调用 wallet.ShardOf(wallet_id),再从配置的 Wallet Node client 集合中选择目标。当前实现只接受可服务 walletid.SingleShard 的单分片配置。
2. PrepareTransfer
Facade TransferService.PrepareTransfer 把银行侧请求映射为 WalletNodeOpsService.PrepareTransfer。
Wallet Node 的处理顺序为:
- 校验 sender / recipients / amounts 等参数;
- 校验钱包权限与同一钱包是否已有 in-flight pending transaction;
- 选择并锁定 UTXO;
- 构造 Token transaction;
- 计算
TokenRequest.MarshalToSign(); - 把
PendingTransaction按tx_id存入进程内 store; - 返回
tx_id、base64 待签数据、金额与费用结果。
pending store 的实现位于 cbdc-token/app/walletnode/internal/biz/biz.go,不是数据库或 Redis 状态。
3. SubmitTransfer
Wallet Node 在解码签名成功后才从 pending store 原子 Pop(tx_id),避免格式错误请求提前丢失 pending transaction。随后 SubmitSignatureView:
- 为普通 X.509 钱包注入预提交签名,或按
key_id处理 policy wallet 签名; - 运行
AuditAndEndorseView; - 广播到 Orderer;
- 把 selector 所有权交给
FinalityRegistry。
成功响应的语义是“广播已接受,终局仍待确认”,不是“账本已经提交”。客户端需要通过交易查询接口轮询 Token SDK 的权威状态。
若广播结果不确定,代码返回 ErrBroadcastUncertain,同时保留锁并交由 finality watcher 决定最终释放或确认,避免重复花费。
4. Endorser 代理审计
AuditAndEndorseView 在银行侧节点运行,但只连接 Endorser。Endorser 的 AuditResponderView 接收交易字节,再通过 RequestAuditView 转给 Auditor。
Auditor 验证交易和规则并返回签名;Wallet Node 验证该签名确实对应公共参数中的 Auditor 身份,然后继续 owner signature、链码背书与分发流程。这个结构使 Wallet Node 无需为每笔交易直接连接 Auditor。
5. Orderer、Committer 与 finality
Submit 主路径在 broadcast 后立即返回。Wallet Node 的 FinalityWorker 异步观察交易:
- 已提交时确认 selector 的已花费状态;
- 明确失败时释放锁;
- 超时或暂时不可判定时继续按 worker 策略处理。
收款方节点通过已注册的 responder 接收交易并等待 finality。FSC P2P 使用 WebSocket + TLS,实际对端由静态 resolver 与 BizHub Node Registry 同步共同维护。
6. 一步式托管转账
TransferDirect 面向私钥由 Wallet Node 持有的托管钱包:它在同一调用中构造交易、使用本地 wallet signer 签名并广播。只有证书、但没有本地私钥的钱包不能走这条路径。
7. Issue 与 Redeem
Issue
Issuer 构造发行交易后同样通过 AuditAndEndorseView 获取审计与背书,再进入排序和终局流程。Wallet Node 注册 AcceptCashView ← IssueCashView,用于接收发行结果。
Redeem
Wallet Node 同时支持 Prepare/Submit 赎回。它和两阶段 Transfer 一样生成待签数据并保存 pending transaction;提交阶段注入外部签名,经审计与背书后广播。结算请求和 RTGS 协调属于 BizHub 业务域,不改变 Token 账本的终局来源。
8. View 注册关系
| 节点 | 主要 responder / initiator 关系 |
|---|---|
| Wallet Node | 接收 transfer / identity / prepared-transfer / cash 等 View;发起 Prepare/Submit/Transfer/Redeem |
| Endorser | AuditResponderView ← AuditAndEndorseView |
| Auditor | AuditView ← RequestAuditView |
| Issuer | 发起 IssueCashView;同步 Auditor/Endorser resolver |
Auditor 与 Endorser 注册自身地址;Issuer 与 Wallet Node 拉取所需节点快照。这不是所有节点都执行的对称注册流程。
9. 部署约束
- Prepare 与 Submit 必须到同一 Wallet Node 实例,除非引入粘性路由或共享 pending store。
- Token driver 取决于配置集:
dev/config/token/*是 zkatdlog,cbdc-token/conf/*是 fabtoken。 SubmitTransfer的成功不等于 finality;调用方应查询交易状态。- Facade 的请求验签与 Token owner signature 是两层不同签名,不能相互替代。
代码入口
cbdc-facade/internal/auth/cbdc-facade/internal/service/transfer.gocbdc-token/app/walletnode/internal/service/transfer_service.gocbdc-token/app/walletnode/internal/biz/transfer_biz.gocbdc-token/pkg/token/views/transfer.gocbdc-token/pkg/token/views/endorsement.gocbdc-token/pkg/token/views/audit.go