Раздел 30 · Web3 на Rust

Корпоративный блокчейн и токенизация: когда реестр нужен, а когда это база данных

middle~40 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Корпоративный блокчейн и токенизация: когда реестр нужен, а когда это база данных

Последний урок блока, и он про самую нехайповую его часть. Компании десять лет запускают блокчейн-пилоты, большинство из которых тихо закрылись. При этом токенизированные фонды и стейблкоины работают и держат миллиарды. Разберёмся, чем одно отличается от другого, и заодно ответим на неприятный вопрос: когда распределённый реестр действительно нужен, а когда это дорогая база данных с лишними шагами.

Тест на необходимость

Начнём с фильтра, который сэкономил бы индустрии годы работы. Распределённый реестр оправдан, когда одновременно выполнены четыре условия:

  1. Несколько сторон, которые пишут в общее состояние.
  2. Они не доверяют друг другу настолько, чтобы отдать реестр одной из них.
  3. Нет приемлемого посредника: либо его нет вовсе, либо он дорог, медлен или сам создаёт риск.
  4. Нужна проверяемая история, а не только текущее значение.

Убери любое условие, и выигрывает обычная база. Одна компания пишет? База. Стороны согласны на арбитра? База под управлением арбитра. Нужна только текущая величина? База с журналом аудита.

Именно на третьем пункте умерло большинство корпоративных пилотов. Внутри одного холдинга посредник есть, он называется головной компанией, и она уже всем управляет. Реестр в таком проекте не решал ни одной задачи, зато добавлял консенсус, узлы и сложность. Обратная сторона тоже верна: там, где условия честно выполняются (несколько независимых банков, торговое финансирование между несвязанными сторонами, цепочка поставок с конкурентами внутри), реестр работает и живёт.

Что меняется, когда участники известны

Сеть с разрешённым доступом устроена иначе публичной по всем осям.

Консенсус берут византийский с известным набором участников: он даёт детерминированную финальность без вероятностного ожидания и без затрат на добычу. Токен и комиссии не нужны, потому что защищаться от спама можно квотами: участники известны поимённо.

Дальше начинается собственно инженерия приватности, и подходы у платформ разные.

Fabric переворачивает привычный порядок исполнения. В Ethereum сначала транзакции упорядочиваются, потом каждый узел их исполняет. Здесь наоборот: сначала нужные организации исполняют предложение и подписывают результат, затем служба упорядочивания складывает подписанные результаты в блок, и только потом узлы проверяют, что подписи соответствуют политике и что прочитанные значения не устарели. Отсюда два следствия: код исполняют не все (значит, данные видят не все) и конфликтующие транзакции отсеиваются на этапе проверки. Приватность доводится каналами (отдельная подсеть со своим реестром) и приватными коллекциями данных, когда в общий реестр уходит только хеш, а сами данные ходят между избранными.

Besu и подобные идут другим путём: это Ethereum, запущенный в закрытом контуре с византийским консенсусом. Знакомая EVM, знакомый инструментарий, приватность через отдельный слой обмена, который хранит зашифрованные полезные нагрузки у участников сделки. Плюс в том, что весь опыт разработки под EVM переносится один в один.

Corda вообще отказывается от общего реестра: данные передаются точка-точка тем, кого сделка касается, а глобальный компонент нужен лишь для того, чтобы никто не потратил один и тот же актив дважды. Формально это уже не блокчейн, зато честно решает задачу финансовых контрактов между двумя сторонами.

Общий вывод: чем ближе к корпоративной реальности, тем сильнее конструкция уходит от «все видят всё» к «видят только участники сделки». А вместе с этим тает и первичное обещание публичной проверяемости.

Токенизация: три слоя, а не один

Токенизация звучит как «записать актив на цепи», а на деле это конструкция из трёх слоёв, и цепь тут самый простой.

Запись на цепи. Токен, отражающий долю. Технически это самая понятная часть.

Юридическая обёртка. Кто именно владеет активом, какое право даёт токен и что говорит суд, если запись на цепи разошлась с реальностью. Обычно актив держит специальная компания, а токен даёт право требования к ней.

Хранитель и связь с реальностью. Кто-то физически хранит золото, недвижимость или ценные бумаги и подтверждает их наличие. Это проблема оракула в чистом виде: цепь не умеет проверить, что в хранилище действительно лежит слиток.

Отсюда трезвая мысль: токенизация не убирает доверие, она переносит его на эмитента и хранителя. Ценность не в отсутствии посредника, а в свойствах записи: делимость, круглосуточные расчёты, мгновенные переводы, программируемость и автоматическое соблюдение правил.

Именно поэтому работают те применения, где базовый актив изначально цифровой и обязательства простые: обеспеченные стейблкоины и токенизированные фонды денежного рынка. И буксуют те, где актив физический, а право сложное: недвижимость, предметы искусства, доли в бизнесе. Технически последнее ничем не труднее, спотыкается юридический и хранительский слой.

Комплаенс становится кодом

Публичный токен переводится кому угодно. Токенизированная ценная бумага так не может: круг держателей ограничен законом. Значит, проверка должна стоять в самом переводе, иначе она не проверка.

/// Статус участника в реестре разрешённых держателей.
#[derive(Clone, Copy, PartialEq, Debug)]
enum Holder {
    Unknown,          // документы не проверены
    Verified { jurisdiction: [u8; 2], accredited: bool },
    Frozen,           // заблокирован по решению эмитента или регулятора
}

#[derive(Debug, PartialEq)]
enum TransferError {
    SenderNotVerified,
    ReceiverNotVerified,
    AccountFrozen,
    JurisdictionNotAllowed,
    AccreditationRequired,
    InsufficientBalance,
    LockupActive { until: u64 },
}

impl SecurityToken {
    /// Правила комплаенса это не документ рядом с кодом, а условие перевода.
    fn transfer(
        &mut self,
        from: &'static str,
        to: &'static str,
        amount: u64,
        now: u64,
    ) -> Result<(), TransferError> {
        let sender = *self.holders.get(from).unwrap_or(&Holder::Unknown);
        let receiver = *self.holders.get(to).unwrap_or(&Holder::Unknown);

        if sender == Holder::Frozen || receiver == Holder::Frozen {
            return Err(TransferError::AccountFrozen);
        }

        let Holder::Verified { .. } = sender else {
            return Err(TransferError::SenderNotVerified);
        };
        let Holder::Verified { jurisdiction, accredited } = receiver else {
            return Err(TransferError::ReceiverNotVerified);
        };

        if !self.allowed_jurisdictions.contains(&jurisdiction) {
            return Err(TransferError::JurisdictionNotAllowed);
        }
        if self.accredited_only && !accredited {
            return Err(TransferError::AccreditationRequired);
        }

        let until = *self.lockup_until.get(from).unwrap_or(&0);
        if now < until {
            return Err(TransferError::LockupActive { until });
        }

        let balance = self.balances.entry(from).or_insert(0);
        if *balance < amount {
            return Err(TransferError::InsufficientBalance);
        }
        *balance -= amount;
        *self.balances.entry(to).or_insert(0) += amount;
        Ok(())
    }
}

Прогон показывает все ветки отказа:

alice -> bob:     Err(AccreditationRequired)
alice -> carol:   Err(JurisdictionNotAllowed)
alice -> dave:    Err(AccountFrozen)
alice -> mallory: Err(ReceiverNotVerified)
bob аккредитован, alice -> bob: Ok(())
bob под запретом продажи: Err(LockupActive { until: 500 })
после срока: Ok(())

Три наблюдения, которые важнее самого кода.

Токен зависит от идентичности. Проверка опирается на реестр держателей, а он наполняется по документам. Здесь и стыкуются DID и верифицируемые удостоверения: держатель предъявляет подписанное удостоверение, а на цепь попадает только факт допуска, без персональных данных. Это единственный известный способ соблюсти правила, не выкладывая паспорта в публичный реестр.

Заморозка и принудительный перевод обязаны существовать. Регулятор требует уметь исполнить решение суда, вернуть украденное, заблокировать санкционного держателя. То есть в токене намеренно есть административная власть. С точки зрения урока про безопасность это большая красная кнопка, и вопрос лишь в том, кто ей владеет и с какой задержкой она срабатывает.

Композиция ломается. Такой токен нельзя просто положить в публичный пул ликвидности: пул это контракт, а он не проходит проверку держателя. Отсюда фундаментальное напряжение всего направления: то, ради чего токенизируют (мгновенная ликвидность и совместимость приложений), режется тем, что требует закон.

премиум-урок

Продолжение в премиуме: 1 200 ₽ в месяц или 10 000 ₽ в год. Вместе с ним серверные проверки задач и школьные токены AI-коуча.

Оплата пока не подключена: премиум и курсы открываются промокодом.