指南

指南 · 第 3 部分,共 6 部分

验证一条记录

验证是 Label 309 中不需要征得任何人同意的那一半。只要给出一个 Cardano 交易引用,你就能自己核实一条记录——基于公开链、通过你自选的区块链浏览器。整个过程无需登录,结果也丝毫不取决于是谁发布了它。

使用 CLI

安装 cardanowall 二进制后,把它指向一笔交易:

cardanowall verify 3b9f…c1a2

它会通过一个公开的 Cardano 区块链浏览器解析这笔交易,对记录做结构校验,核查所有作者身份签名,确认记录已结算,并打印出一个结论。这个结论是四种状态之一,退出码会原原本本地把它带出来,所以它能直接接入 CI:

退出码结论含义
0valid每一项必需的检查都通过了
1failed一项可归因于记录的检查失败了(完整性、结构或签名)
2unverifiable不是记录的过错,但某项必需的检查无法运行(网络或策略)
3pending确认数还不够——来自一条 pending 记录的结果都不是最终的
4CLI 输入错误(参数有误或缺少必需输入)

failedunverifiable 之间的区分是刻意为之的:一个 failed 结论总是可归因于记录本身,因此没有哪个行为不端的浏览器能制造出一个;unverifiable 则意味着验证器因记录之外的原因无法完成某项检查——一个它够不着的网关、一个被列入 deny 名单的主机,或一道拉取上限。

加上 --json 可得到机器可读的报告;把工具指向你自己的基础设施,就能让每一跳网络请求都在你的掌控之中:

cardanowall verify 3b9f…c1a2 \
  --cardano-gateway https://your-koios-instance/api/v1 \
  --threshold 20 \
  --json

如果这条记录是密封给你的,把你的密钥交给验证器,它就会解密载荷并重新计算明文哈希:

cardanowall verify 3b9f…c1a2 --secret-key-stdin

优先使用 --secret-key-stdin--secret-key-fileCARDANOWALL_RECIPIENT_KEY 环境变量,而不是直接用 --secret-key 标志,这样密钥就不会落入你的 shell 历史。

使用 TypeScript SDK

CLI 用的那个验证器就内置在 SDK 里。它不需要客户端、不需要基础 URL,也不需要密钥——验证不依赖网关:

import { verifyTx } from '@cardanowall/sdk-ts/verifier';

const report = await verifyTx({ txHash: '3b9f…c1a2' });

console.log(report.verdict); // 'valid' | 'pending' | 'unverifiable' | 'failed'

if (report.verdict !== 'valid') {
  console.error(report.issues, report.signatures);
}

verifyTx 会返回一份完整的 VerifyReport:结论和 exitCode、解析出的 block_timeconfirmationDepth、结构校验与验证器合并的 issues 列表、逐项的 itemsmerkle 检查结果、可选的 signatures,以及它发出的每一次对外请求的 auditTrail 日志——你可以据此向自己证明,它从未联系过发布者。

要验证一条密封给你的记录,把你的私钥交给验证器。密钥环在整次运行中是全局的——你传入的每一把密钥都会被对每一个密封项逐一尝试,因此没有逐项索引:

const report = await verifyTx({
  txHash: '3b9f…c1a2',
  decryption: [{ recipientSecretKey: mySecretKey }],
});

使用 Python SDK

cardanowall-sdk 是 TypeScript 验证器逐字节一致的孪生实现——同样的检查,同样的结论:

import asyncio
import cardanowall

report = asyncio.run(cardanowall.verify_tx(cardanowall.VerifyTxInput(tx_hash="3b9f…c1a2")))
print(report.verdict)

使用 Rust SDK

cardanowall crate 也带着同一个验证器。verify_tx 是同步的——它内部持有一个阻塞式传输——并返回同样的 VerifyReport

use cardanowall::verifier::{verify_tx, Verdict, VerifyTxInput};

let report = verify_tx(&VerifyTxInput::new("3b9f…c1a2"));

println!("{}", report.verdict.as_str()); // "valid" | "pending" | "unverifiable" | "failed"

if report.verdict != Verdict::Valid {
    eprintln!("{:?}", report.issues);
    eprintln!("{:?}", report.record_signatures);
}

要验证一条密封给你的记录,附上你的私钥。密钥环在整次运行中是全局的——每一把密钥都会被对每一个密封项逐一尝试,因此一份凭据不携带任何项索引。输入字段都是公开的,因此可以在 VerifyTxInput::new 之上继续构建:

use cardanowall::verifier::{verify_tx, Decryption, VerifyTxInput};

let mut input = VerifyTxInput::new("3b9f…c1a2");
input.decryption = Some(vec![Decryption::Recipient {
    recipient_secret_key: my_secret_key, // Vec<u8>
}]);

let report = verify_tx(&input);

为什么这件事不需要信任

每一项检查都基于公开数据和你自选的区块链浏览器运行。发布这条记录的人无法左右结果——就算他们明天就消失了,你的验证照样能跑出一模一样的结果。