Руководства

Руководства · Часть 2 из 6

Опубликуйте своё первое подтверждение существования

Публикация — та сторона Label 309, для которой шлюз действительно нужен. Проверка не требует доверия и работает без аккаунта; публикация же помещает транзакцию в блокчейн, а это стоит комиссии. Поэтому отправка идёт через шлюз Label 309: он собирает транзакцию, оплачивает комиссию и списывает средства по собственной балансовой модели. SDK и CLI не привязаны к конкретному шлюзу — направьте их на тот, для которого у вас есть API-ключ.

Каждая публикация устроена одинаково и состоит из двух шагов: зафиксировать цену, затем отправить. Шлюз рассчитывает стоимость записи по актуальному снимку валютного курса и возвращает quote_id, который действует 15 минут; вызов публикации атомарно расходует его одновременно с добавлением записи в блокчейн. Высокоуровневые помощники хешируют содержимое и формируют каноническую 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_URL и CARDANOWALL_API_KEY либо из сохранённого профиля шлюза, так что в CI их можно из команды убрать. Если хеш у вас уже есть, закрепите его напрямую через --hash вместо --file; добавьте --alg blake2b-256, чтобы переключиться с алгоритма по умолчанию sha2-256, и --json — для машиночитаемой сводки:

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

Чтобы подписать запись ключом вашей идентичности, передайте 32-байтовый мастер-сид через --seed-file или --seed-stdin (никогда не передавайте сид напрямую через --seed в аргументах командной строки — он осядет в истории оболочки). Опустите этот параметр, чтобы опубликовать запись без подписи.

Через 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_hash остаётся null, пока шлюз не соберёт транзакцию. Передайте 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 предоставляет тот же клиент, не привязанный к конкретному шлюзу. Вызовы блокирующие, так что асинхронная среда выполнения не нужна; помощники возвращают типизированные результаты:

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 под меткой 309. Любой может проверить её по одному только публичному блокчейну, без аккаунта и без доверия к шлюзу. Чтобы вместо этого адресовать запись получателю, см. раздел Создайте запечатанное подтверждение существования; точный вид записи в блокчейне описан в разделе Запись.