Solana签名覆盖整条Message,其中包含recent blockhash。这个哈希既帮助防止交易无限重放,也给交易设置有效窗口。用户签名后若长时间不发送,验证者会把消息视为过期,即使签名本身完全正确。
不要用固定分钟数判断过期
getLatestBlockhash返回blockhash和lastValidBlockHeight。客户端应持续读取当前block height,与lastValidBlockHeight比较;slot可能跳过,墙钟时间也受网络状况影响,不能用“签名后90秒”替代协议字段。
安全确认状态机
已发送,未到有效高度
重复广播同一已签名交易通常不会造成两次不同交易,因为签名相同。可以向多个健康RPC重发原字节,并查询signature status。此时不要换blockhash重新签名。
RPC超时,但链上状态未知
超时只说明客户端没收到结果。继续查询签名,并检查业务状态,例如目标余额或程序事件。若立即生成新交易,原交易和新交易可能都在不同时间成功。
已超过lastValidBlockHeight
确认原签名未落链后,重新读取最新blockhash,重新构造Message并让所有签名者重新签名。新Message会产生新签名,应用要把它与原业务请求关联,同时阻止重复业务执行。
| 错误 | 含义 | 下一步 |
|---|---|---|
| Blockhash not found | 节点不知道或不接受该哈希 | 检查节点是否落后及哈希有效性 |
| transaction expired | 已超过有效高度 | 查询旧签名后再重签 |
| signature not found | 可能未广播或节点视图不同 | 换健康节点继续查 |
| processed未confirmed | 已有执行迹象但稳定性不足 | 不要重签,继续确认 |
节点落后会制造假象
从较新的节点取得blockhash,却向明显落后的节点发送,后者可能尚未见过该哈希;反过来,从落后节点取得的哈希可能在领导者看来已经太旧。获取、发送和确认最好使用健康且视图接近的RPC,并比较它们的slot高度。
业务层还要防重
链上blockhash只限制同一Message。应用重新构造后是另一笔交易,因此支付、铸币或订单程序应有自己的request id、nonce或幂等账户。多签与离线签名流程若预计等待很久,应考虑Durable Nonce,而不是不断刷新recent blockhash。
重签前先判断旧交易是否仍可能落地
lastValidBlockHeight用于判断recent blockhash的有效窗口,但RPC节点可能落后或位于不同分叉。客户端应使用与发送端一致且健康的节点查询当前block height和签名状态;仅因本地超时就重签,可能让旧交易与新交易都被执行。
对于转账等不可重复业务,可在程序层加入唯一业务编号、状态账户或一次性nonce,使第二次执行安全失败。Durable Nonce适合需要离线签名或更长提交窗口的场景,但必须在交易中推进nonce,并处理nonce账户权限;它不是简单延长普通blockhash。
slot与block height区别见Solana时间单位,模拟和正式发送见simulateTransaction,离线签名可参考Solana Durable Nonce。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。