指南

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

发布你的第一份 PoE

发布是 Label 309 中确实需要网关的那一半。验证无需信任、无需账号;而发布要把一笔交易写到链上,这会产生手续费——所以你要通过一个 Label 309 网关来提交,由网关构建交易、支付手续费,并从它自己的余额模型中扣款。SDK 和 CLI 都不依赖特定网关:你持有哪个网关的 API 密钥,就把它们指向那个网关。

每次发布都是同样的两步——先锁定价格,再提交。网关依据一份实时汇率快照为记录定价,并返回一个有效期 15 分钟的 quote_id;发布调用会在执行链上写入的同时,原子性地消费这个报价。上层辅助函数会替你对内容进行哈希,并构建规范 CBOR 记录。

使用 CLI

安装 cardanowall 二进制后,把 submit 指向一个文件。它会对文件内容进行哈希、锚定摘要,并打印结果:

cardanowall submit \
  --file ./contract.pdf \
  --base-url https://your-gateway.example \
  --api-key "$CW_API_KEY"

--base-url--api-key 也会从 CARDANOWALL_BASE_URLCARDANOWALL_API_KEY 环境变量、或一份已保存的网关配置中读取,因此在 CI 里可以从命令中省去它们。如果你已经持有摘要,可直接用 --hash 代替 --file 来锚定;加上 --alg blake2b-256 即可从默认的 sha2-256 切换算法,加上 --json 则输出机器可读的摘要:

cardanowall submit --hash 3b9f…c1a2 --json

如需用你的身份密钥为记录签名,请通过 --seed-file--seed-stdin 传入 32 字节的主种子(切勿在命令行参数里直接写 --seed——它会落入 shell 历史)。省略它则发布未签名的记录。

使用 TypeScript SDK

针对你的网关构建一个客户端,然后用一次辅助函数调用完成报价和发布。publishContent 会对字节进行哈希、构建记录并提交:

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

const client = new Label309Client({
  baseUrl: 'https://your-gateway.example',
  apiKey: process.env.CW_API_KEY,
});

const quote = await client.poe.quote({
  recordBytes: 256,
  recipientCount: 0,
  fileBytesTotal: 0,
});

const result = await client.poe.publishContent({
  content: fileBytes, // Uint8Array or a UTF-8 string
  quoteId: quote.quote_id,
  // idempotencyKey: crypto.randomUUID(), // safe to retry the same submit
  // signer is optional — omit to publish unsigned (profile=core)
});

console.log(result.id, result.tx_hash, result.status);
console.log(result.balance_after_usd_micros); // decimal string of USD micro-cents

result.status 的初始值是 submitting;在网关构建出交易之前,tx_hashnull。传入 idempotencyKey 可让重试变得安全——重复提交相同的内容会返回原来那条记录(dedup_hit: true),不会重复扣款。若使用预先算好的摘要,用 publishPrehashed;若要发布密封给某接收方的信封,用 publishSealed

使用 Python SDK

cardanowall-sdk 与 TypeScript 的辅助函数一一对应。客户端是一个异步上下文管理器;响应以普通字典的形式返回:

import asyncio
from cardanowall.client import Label309Client


async def main() -> None:
    async with Label309Client(
        base_url="https://your-gateway.example",
        api_key="<opaque-bearer>",
    ) as client:
        quote = await client.poe.quote(
            record_bytes=256, recipient_count=0, file_bytes_total=0
        )
        out = await client.poe.publish_content(
            content="hello world",  # str (UTF-8) or bytes
            quote_id=quote["quote_id"],
        )
        print(out["id"], out["tx_hash"], out["status"])


asyncio.run(main())

使用 Rust SDK

cardanowall crate 提供同样不依赖网关的客户端。调用是阻塞式的,因此不需要异步运行时;辅助函数返回带类型的结果:

use cardanowall::client::{
    Label309Client, Label309ClientConfig, PublishContentInput, QuoteInput,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Label309Client::new(Label309ClientConfig {
        base_url: Some("https://your-gateway.example".into()),
        api_key: std::env::var("CW_API_KEY").ok(),
    })?;

    let quote = client.poe().quote(&QuoteInput {
        record_bytes: 256,
        recipient_count: 0,
        file_bytes_total: 0,
    })?;

    let result = client.poe().publish_content(&PublishContentInput {
        content: file_bytes, // Vec<u8>
        quote_id: quote.quote_id,
        hash_alg: None, // defaults to sha2-256
        signer: None,   // omit to publish unsigned (profile = core)
        idempotency_key: None,
    })?;

    println!("{} {:?} {:?}", result.id, result.tx_hash, result.status);
    Ok(())
}

若使用预先算好的摘要,用 publish_prehashed;若要发布密封给某接收方的信封,用 publish_sealed

手续费是网关的,证明是你的

你借以发布的网关会支付 Cardano 手续费,并从它的余额模型中扣款——但它锚定的那条记录,只是写在 label 309 下的普通 Label 309 元数据。任何人都可以仅凭公开链上数据来验证它,无需账号,也无需信任这个网关。若想把记录发给某个接收方,参见构建一份密封 PoE;想了解确切的链上结构,请阅读记录