name: Протокол RGB, от теории к практике goal: Приобретите навыки, необходимые для понимания и использования RGB objectives:
- Понять фундаментальные концепции протокола RGB
- Освойте принципы проверки на стороне клиента и обязательств Bitcoin
- Узнайте, как создавать, управлять и передавать контракты RGB
- Как управлять RGB-совместимым узлом Lightning
Открытие протокола RGB
Погрузитесь в мир RGB - протокола, предназначенного для реализации и обеспечения соблюдения цифровых прав в форме контрактов и активов на основе правил консенсуса и операций блокчейна Bitcoin. Этот комплексный учебный курс проведет вас через технические и практические основы RGB, от концепций "проверки на стороне клиента" и "одноразовых печатей" до реализации продвинутых смарт-контрактов.
Благодаря структурированной пошаговой программе вы узнаете о механизмах проверки на стороне клиента, детерминированных обязательствах в Bitcoin и схемах взаимодействия между пользователями. Узнайте, как создавать, управлять и передавать токены RGB в Bitcoin или Lightning Network.
Если вы разработчик, энтузиаст биткойна или просто хотите узнать больше об этой технологии, этот учебный курс предоставит вам инструменты и знания, необходимые для освоения RGB и создания инновационных решений на базе биткойна.
Курс основан на живом семинаре, организованном Fulgur'Ventures, и проводится тремя известными преподавателями и экспертами в области RGB.
Введение
Презентация курса
Всем привет и добро пожаловать на этот учебный курс, посвященный RGB, системе смарт-контрактов с клиентским подтверждением, работающей на Bitcoin и Lightning Network. Структура курса разработана таким образом, чтобы обеспечить глубокое изучение этой сложной темы. Вот как организован курс:
**Раздел 1: Теория
Первый раздел посвящен теоретическим концепциям, необходимым для понимания основ валидации на стороне клиента и RGB. Как вы узнаете из этого курса, RGB вводит множество технических концепций, которые обычно не встречаются в Биткойне. В этом разделе вы также найдете глоссарий, содержащий определения всех терминов, характерных для протокола RGB.
**Раздел 2: Практика
Второй раздел будет посвящен применению теоретических концепций, рассмотренных в первом разделе. Мы узнаем, как создавать RGB-контракты и манипулировать ими. Также мы увидим, как программировать с помощью этих инструментов. Эти первые два раздела представлены Максимом Орловским.
**Раздел 3: Приложения
В заключительном разделе выступают другие докладчики, которые представляют конкретные приложения на основе RGB, чтобы подчеркнуть реальные примеры использования.
Этот учебный курс первоначально вырос из двухнедельного буткемпа по продвинутой разработке в Виареджо, Тоскана, организованного Fulgur'Ventures. Первую неделю, посвященную Rust и SDK, можно найти в этом другом курсе:
https://planb.network/courses/9fbd8b57-f278-4304-8d88-a2d384eaff58
В этом курсе мы сосредоточимся на второй неделе буткемпа, которая посвящена RGB.
Неделя 1 - LNP402:
Неделя 2 - Текущее обучение CSV402:
Большое спасибо организаторам этих живых курсов и 3 преподавателям, которые приняли в них участие:
- Максим Орловский: Ex Tenebrae sententia sapiens dominabitur astris. Сайфер, ИИ, робототехника, трансгуманизм. Создатель RGB, Prime, Radiant и lnp_bp, mycitadel_io & cyphernet_io ;
- Хантер Трухило: Разработчик, Rust, Bitcoin, Lightning, RGB ;
- Федерико Тенга: Я вношу свою лепту в превращение мира в антиутопию в стиле киберпанк. В настоящее время работаю над RGB в Bitfinex.
Письменная версия этого учебного курса была составлена с использованием двух основных ресурсов:
- Видеозаписи семинара Максима Орловского, Хантера Трухило и Фредерико Тенги на Lightning Bootcamp ;
- Документация RGB, выпуск которой спонсировала компания Bitfinex.
Готовы погрузиться в сложный и увлекательный мир RGB? Вперёд!
RGB в теории
Введение в концепции распределенных вычислений
RGB - это протокол, предназначенный для применения и обеспечения соблюдения цифровых прав (в форме контрактов и активов) масштабируемым и конфиденциальным способом, основанным на правилах консенсуса и операциях блокчейна Bitcoin. Цель этой первой главы - представить основные понятия и терминологию, связанные с протоколом RGB, подчеркнув, в частности, его тесную связь с основными концепциями распределенных вычислений, такими как проверка на стороне клиента и одноразовые печати.
В этой главе мы изучим основы систем распределенного консенсуса и посмотрим, как RGB вписывается в это семейство технологий. Мы также представим основные принципы, которые помогут нам понять, почему RGB стремится быть расширяемым и независимым от собственного механизма консенсуса Bitcoin, но при этом полагаться на него в случае необходимости.
Введение
Распределенные вычисления, отдельная отрасль компьютерной науки, изучает протоколы, используемые для циркуляции и обработки информации в сети узлов. Вместе эти узлы и правила протоколов образуют так называемую распределенную систему. Среди основных свойств, характеризующих такую систему, можно назвать следующие:
- Возможность независимой проверки и подтверждения** определенных данных каждым узлом;
- Возможность для узлов построить (в зависимости от протокола) полное или частичное представление информации. Эти представления являются состояниями распределенной системы;
- хронологический порядок операций, чтобы данные были надежно привязаны по времени и существовал консенсус относительно последовательности событий (последовательности состояний).
В частности, понятие консенсуса в распределенной системе охватывает два аспекта:
- Признание достоверности** изменений состояния (в соответствии с правилами протокола);
- Согласование порядка** этих изменений состояния, что делает невозможным переписать или отменить подтвержденные операции апостериори (это также известно в Биткойне как "защита от двойной траты").
Первая функциональная реализация механизма распределенного консенсуса без права доступа была представлена Сатоши Накамото в биткойне благодаря совместному использованию структуры данных блокчейн и алгоритма Proof-of-Work (PoW). В этой системе достоверность истории блока зависит от вычислительной мощности узлов (майнеров). Таким образом, биткойн является важным и историческим примером распределенной системы консенсуса, открытой для всех (permissionless).
В мире блокчейна и распределенных вычислений можно выделить две фундаментальные парадигмы: блокчейн в традиционном понимании и государственные каналы, лучшим примером которых в производстве является Lightning Network. Блокчейн определяется как реестр хронологически упорядоченных событий, воспроизводимых на основе консенсуса в открытой, свободной от прав доступа сети. Каналы состояния, с другой стороны, представляют собой одноранговые каналы, которые позволяют двум (или более) участникам поддерживать обновленное состояние вне цепи, используя блокчейн только при открытии и закрытии этих каналов.
В контексте Биткойна вы, несомненно, знакомы с принципами майнинга, децентрализации и окончательности транзакций в блокчейне, а также с тем, как работают платежные каналы. В RGB мы вводим новую парадигму под названием Client-side Validation, которая, в отличие от блокчейна или Lightning, заключается в локальном (на стороне клиента) хранении и проверке переходов состояния смарт-контракта. Она также отличается от других "DeFi" техник (rollups, plasma, ARK и т.д.) тем, что Client-side Validation опирается на блокчейн для предотвращения двойных трат и систему временных меток, сохраняя реестр состояний и переходов вне цепи только у соответствующих участников.
Позже мы также введем важный термин: понятие "stash", которое обозначает набор данных на стороне клиента, необходимых для сохранения состояния контракта, поскольку эти данные не реплицируются глобально по всей сети. Наконец, мы рассмотрим обоснование RGB, протокола, использующего преимущества клиентской валидации, и то, почему он дополняет существующие подходы (блокчейн и каналы состояния).
Трилеммы в распределенных вычислениях
Чтобы понять, как Client-side Validation и RGB решают проблемы, не решенные блокчейном и Lightning, давайте откроем для себя 3 основные "трилеммы" в распределенных вычислениях:
- Масштабируемость, децентрализация, конфиденциальность** ;
- Теорема CAP** (согласованность, доступность, устойчивость к разбиению) ;
- Трилемма CIA** (Confidentiality, Integrity, Availability).
1. Масштабируемость, децентрализация и конфиденциальность
- Блокчейн (биткойн)**
Блокчейн очень децентрализован, но не очень масштабируем. Более того, поскольку все хранится в глобальном публичном реестре, конфиденциальность ограничена. Мы можем попытаться улучшить конфиденциальность с помощью технологий нулевого знания (конфиденциальные транзакции, схемы mimblewimble и т. д.), но публичная цепочка не может скрыть граф транзакций.
- Молния/Государственные каналы**
Государственные каналы (как, например, Lightning Network) более масштабируемы и более приватны, чем блокчейн, поскольку транзакции происходят вне цепи. Однако обязательство публично объявлять о некоторых элементах (транзакции финансирования, топология сети) и мониторинг сетевого трафика могут частично нарушить конфиденциальность. Децентрализация также страдает: маршрутизация требует больших денежных затрат, а крупные узлы могут стать центральными точками. Именно это явление мы начинаем наблюдать на Lightning.
- Проверка на стороне клиента (RGB)**
Эта новая парадигма еще более масштабируема и более конфиденциальна, поскольку мы не только можем интегрировать методы доказательства знания с нулевым разглашением, но и не существует глобального графа транзакций, поскольку никто не владеет всем реестром. С другой стороны, это также подразумевает определенный компромисс в отношении децентрализации: эмитент смарт-контракта может играть центральную роль (как "развертыватель контракта" в Ethereum). Однако, в отличие от блокчейна, при Client-side Validation вы храните и проверяете только те контракты, которые вас интересуют, что улучшает масштабируемость за счет отсутствия необходимости загружать и проверять все существующие состояния.
2. Теорема CAP (согласованность, доступность, устойчивость к разбиению)
Теорема CAP подчеркивает, что невозможно, чтобы распределенная система одновременно удовлетворяла требованиям согласованности (Consistency), доступности (Availability) и устойчивости к разделам (Partition tolerance).
- Блокчейн**
Блокчейн предпочитает последовательность и доступность, но не очень хорошо справляется с разделением сети: если вы не видите блок, вы не можете действовать и иметь то же представление, что и вся сеть.
- Молния** (на французском языке)
Система государственных каналов обладает устойчивостью к доступности и разделению (поскольку два узла могут оставаться связанными друг с другом даже при фрагментации сети), но общая согласованность зависит от открытия и закрытия каналов в блокчейне.
- Проверка на стороне клиента (RGB)**
Система, подобная RGB, обеспечивает согласованность (каждый участник проверяет свои данные локально, без двусмысленности) и устойчивость к разбиению (вы храните свои данные автономно), но не гарантирует глобальной доступности (каждый должен убедиться, что у него есть соответствующие части истории, и некоторые участники могут ничего не публиковать или перестать делиться определенной информацией).
3. Трилемма CIA (конфиденциальность, целостность, доступность)
Эта трилемма напоминает нам о том, что конфиденциальность, целостность и доступность не могут быть оптимизированы одновременно. Блокчейн, Lightning и Client-side Validation по-разному вписываются в этот баланс. Идея заключается в том, что ни одна система не может обеспечить все; необходимо объединить несколько подходов (временную метку блокчейна, синхронный подход Lightning и локальную проверку с помощью RGB), чтобы получить целостный пакет, предлагающий хорошие гарантии в каждом измерении.
Роль блокчейна и понятие шардинга
Блокчейн (в данном случае Bitcoin) служит в первую очередь как механизм временной маркировки и защиты от двойных трат. Вместо того чтобы вставлять полные данные смарт-контракта или децентрализованной системы, мы просто включаем криптографические обязательства (commitments) транзакций (в смысле Client-side Validation, которые мы будем называть "переходами состояний"). Таким образом
- Мы освобождаем блокчейн от большого количества данных и логики;
- Каждый пользователь хранит только историю, необходимую для его собственной части контракта (его "shard"), вместо того чтобы копировать глобальное состояние.
Шардинг - это концепция, которая зародилась в распределенных базах данных (например, MySQL для социальных сетей, таких как Facebook или Twitter). Чтобы решить проблему объема данных и задержек синхронизации, база данных сегментируется на осколки (США, Европа, Азия и т. д.). Каждый сегмент локально согласован и лишь частично синхронизирован с остальными.
Для смарт-контрактов типа RGB мы разбиваем на шарды в соответствии с самими контрактами. Каждый контракт является независимым шардом. Например, если вы держите только токены USDT, вам не нужно хранить или подтверждать всю историю другого токена, например USDC. В биткойне блокчейн не делает шардинга: у вас есть глобальный набор UTXO. При валидации на стороне клиента каждый участник сохраняет только те данные контракта, которые он держит или использует.
Поэтому мы можем представить себе экосистему следующим образом:
- Блокчейн (Bitcoin)** как основа, обеспечивающая полную репликацию минимального реестра и служащая слоем временной маркировки;
- Сеть Lightning Network** для быстрых конфиденциальных транзакций, по-прежнему основанная на безопасности и окончательных расчетах блокчейна Bitcoin;
- RGB и Client-side Validation** для добавления более сложной логики смарт-контракта без загромождения блокчейна и потери конфиденциальности.
Эти три элемента образуют треугольное целое, а не линейный стек из "слоя 2", "слоя 3" и так далее. Lightning может напрямую подключаться к Bitcoin или быть связанной с транзакциями Bitcoin, включающими данные RGB. Аналогичным образом, использование "BiFi" (финансы на Bitcoin) может быть связано с блокчейном, Lightning и RGB в соответствии с требованиями к конфиденциальности, масштабируемости или логике контракта.
Понятие переходов между состояниями
В любой распределенной системе целью механизма проверки является возможность определить достоверность и хронологический порядок изменений состояния. Цель состоит в том, чтобы проверить, что правила протокола были соблюдены, и доказать, что эти изменения состояния следуют друг за другом в определенном, неприступном порядке.
Чтобы понять, как работает эта проверка в контексте Bitcoin и, в целом, понять философию, лежащую в основе Client-side Validation, давайте сначала рассмотрим механизмы блокчейна Bitcoin, а затем увидим, чем Client-side Validation отличается от них и какие оптимизации она дает.
В случае с блокчейном Bitcoin проверка транзакций основана на простом правиле:
- Все узлы сети загружают каждый блок и транзакцию;
- Они проверяют эти транзакции, чтобы убедиться в правильности эволюции набора UTXO (все неизрасходованные выходы);
- Они хранят эти данные (в виде блоков), чтобы при необходимости можно было воспроизвести историю.
Однако у этой модели есть два существенных недостатка:
- Масштабируемость**: поскольку каждый узел должен обрабатывать, проверять и архивировать транзакции каждого, существует очевидный предел пропускной способности транзакций, связанный, в частности, с максимальным размером блока (1 МБ в среднем за 10 минут для Bitcoin, без учета cookies);
- Конфиденциальность**: все передается и хранится в открытом виде (суммы, адреса назначения и т. д.), что ограничивает конфиденциальность обмена.
На практике эта модель подходит для Bitcoin в качестве базового уровня (Layer 1), но может оказаться недостаточной для более сложных применений, требующих одновременно высокой пропускной способности транзакций и определенной степени конфиденциальности.
В основе клиентской валидации лежит противоположная идея: вместо того чтобы требовать от всей сети валидировать и хранить все транзакции, каждый участник (клиент) будет валидировать только ту часть истории, которая касается его или ее:
- Когда человек получает актив (или любую другую цифровую собственность), ему нужно лишь узнать и проверить цепочку операций (переходов состояний), которые привели к появлению этого актива, и доказать его легитимность;
- Эта последовательность операций, начиная с генезиса (первоначального выпуска) и заканчивая самой последней транзакцией, образует ациклический направленный граф (DAG) или шард, т.е. часть общей истории.
В то же время, чтобы остальная часть сети (точнее, базовый уровень, такой как Bitcoin) могла зафиксировать конечное состояние, не видя деталей этих данных, Client-side Validation опирается на понятие commitment.
Коммитмент" - это криптографическое обязательство, обычно хэш (например, SHA-256), вставляемый в транзакцию Биткойна, который доказывает, что в нее были включены приватные данные, не раскрывая их.
Благодаря этим обязательствам мы можем доказать:
- Существование информации (поскольку она зафиксирована в хэше);
- Заблаговременность этой информации (поскольку она привязана к блокчейну и имеет временную метку, дату и порядок блоков).
Однако точное содержание не раскрывается, что позволяет сохранить конфиденциальность.
Если говорить конкретно, то вот как происходит переход в состояние RGB:
- Вы готовите новый переход состояния (например, передачу маркера RGB);
- Вы генерируете криптографическое обязательство по этому переходу и вставляете его в транзакцию Биткойна (в протоколе RGB эти обязательства называются "якорями");
- Контрагент (получатель) извлекает историю клиента, связанную с этим активом, и проверяет сквозную последовательность, от возникновения смарт-контракта до перехода, который вы ему передаете.
Удостоверение на стороне клиента дает два основных преимущества:
- Масштабируемость:**
Обязательства (commitments), включенные в блокчейн, имеют небольшой размер (порядка нескольких десятков байт). Это позволяет не переполнять пространство блока, так как в него нужно включать только хэш. Это также позволяет развиваться внецепочечному протоколу, поскольку каждый пользователь должен хранить только свой фрагмент истории (свой стэш).
- Конфиденциальность :**
Сами транзакции (то есть их подробное содержание) не публикуются на цепочке. Публикуются только их отпечатки (hash). Таким образом, суммы, адреса и логика контрактов остаются приватными, а получатель может локально проверить валидность своего шарда, просмотрев все предыдущие транзакции. У получателя нет причин обнародовать эти данные, кроме как в случае спора или когда требуется доказательство.
В системе, подобной RGB, несколько переходов состояния из разных контрактов (или разных активов) могут быть объединены в одну транзакцию Биткойна с помощью одного коммитмента. Этот механизм устанавливает детерминированную, отмеченную временем связь между транзакцией на цепи и данными вне цепи (подтвержденными переходами на стороне клиента) и позволяет одновременно регистрировать несколько шардов в одной точке привязки, что еще больше снижает стоимость и площадь цепи.
На практике, когда эта транзакция Bitcoin подтверждается, она навсегда "блокирует" состояние базовых контрактов, поскольку изменить хэш, уже записанный в блокчейн, становится невозможно.
Концепция тайника
Тайник** - это набор данных на стороне клиента, которые участник должен обязательно сохранить для поддержания целостности и истории смарт-контракта RGB. В отличие от канала Lightning, где определенные состояния могут быть восстановлены локально из общей информации, тайник контракта RGB не реплицируется в других местах: если вы его потеряете, никто не сможет вам его восстановить, так как вы отвечаете за свою часть истории. Именно поэтому в RGB необходимо внедрить систему с надежными процедурами резервного копирования.
Одноразовая печать: возникновение и эксплуатация
При приеме такого актива, как валюта, необходимы две гарантии:
- Подлинность полученного товара;
- Уникальность полученного товара, чтобы избежать двойных расходов.
Для физических активов, таких как банкнота, достаточно физического присутствия, чтобы доказать, что она не была продублирована. Однако в цифровом мире, где активы носят исключительно информационный характер, такая проверка сложнее, поскольку информация может легко размножаться и дублироваться.
Как мы видели ранее, раскрытие отправителем истории переходов состояний позволяет нам гарантировать подлинность токена RGB. Имея доступ ко всем транзакциям, начиная с генезисной транзакции, мы можем подтвердить подлинность токена. Этот принцип похож на принцип биткойна, где история монет может быть прослежена до первоначальной транзакции на coinbase, чтобы проверить их подлинность. Однако, в отличие от Bitcoin, история переходов состояний в RGB является приватной и хранится на стороне клиента.
Чтобы предотвратить двойную трату жетонов RGB, мы используем механизм под названием "Пломба одноразового использования". Эта система гарантирует, что каждый токен, использованный один раз, не может быть мошеннически использован во второй раз.
Одноразовые пломбы - это криптографические примитивы, предложенные в 2016 году Питером Тоддом, схожие с концепцией физических пломб: после наложения пломбы на контейнер его невозможно открыть или модифицировать без необратимого нарушения пломбы.
Этот подход, перенесенный в цифровой мир, позволяет доказать, что
последовательность событий действительно имела место и что ее уже нельзя
изменить задним числом. Таким образом, одноразовые печати выходят за рамки
простой логики хэш + временная метка, добавляя понятие печати,
которая может быть закрыта только один раз.
Для работы одноразовых печатей необходим носитель информации, способный доказать наличие или отсутствие публикации, и его трудно (если не невозможно) подделать после распространения информации. Эту роль может выполнять блокчейн (например, биткойн), а также, например, бумажная газета с общественным тиражом. Идея заключается в следующем:
- Мы хотим доказать, что определенное обязательство по сообщению
h(m)было опубликовано для аудитории без раскрытия содержания сообщенияm; - Мы хотим доказать, что вместо сообщения
h(m')не было опубликовано никакого другого конкурирующего сообщенияh(m); - Мы также хотим иметь возможность проверить, что сообщение
mсуществует до определенной даты.
Блокчейн идеально подходит для этой роли: как только транзакция включается в блок, у всей сети есть одно и то же нефальсифицируемое доказательство ее существования и содержания (по крайней мере, частично, поскольку обязательство может скрывать детали, доказывая подлинность сообщения).
Таким образом, печать одноразового использования можно рассматривать как официальное обещание опубликовать сообщение (пока еще неизвестное на данном этапе) один и только один раз, причем таким образом, чтобы его могли проверить все заинтересованные стороны.
В отличие от простых коммитментов (хэшей) или временных меток, которые подтверждают дату существования, одноразовая печать дает дополнительную гарантию того, что нет альтернативных обязательств: вы не можете дважды закрыть одну и ту же печать или попытаться заменить запечатанное сообщение.
Следующее сравнение помогает понять этот принцип:
- Криптографическое обязательство (хэш)**: С помощью хэш-функции вы можете взять на себя обязательство хранить часть данных (число), опубликовав его хэш. Данные остаются секретными до тех пор, пока вы не раскроете предварительный образ, но вы можете доказать, что знали их заранее;
- Временная метка (блокчейн)**: Вставляя этот хэш в блокчейн, мы также доказываем, что знали его в определенный момент (момент включения в блок);
- Одноразовая пломба**: С одноразовыми печатями мы идем на шаг дальше, делая обязательство уникальным. С помощью одного хэша можно параллельно создать несколько противоречащих друг другу обязательств (проблема врача, который объявляет семье "Это мальчик", а в личном дневнике пишет "Это девочка"). Одноразовая печать устраняет эту возможность, связывая обязательство с носителем доказательства публикации, таким как блокчейн Биткойна, так что трата UTXO окончательно скрепляет обязательство. Потратив UTXO, нельзя повторно потратить те же самые UTXO, чтобы заменить обязательство.
| Простое обязательство (дайджест/хеш) | Метки времени | Одноразовые печати | |
|---|---|---|---|
| Публикация обязательства не раскрывает сообщение | Да | Да | Да |
| Доказательство даты обязательства / существования сообщения до определённой даты | Невозможно | Возможно | Возможно |
| Доказательство того, что не может существовать альтернативное обязательство | Невозможно | Невозможно | Возможно |
Одноразовые пломбы работают в три основных этапа:
** Определение уплотнения :**
- Алиса заранее определяет правила публикации печати (когда, где и как будет опубликовано сообщение);
- Боб принимает или признает эти условия.
Закрытие :
- Во время выполнения Алиса закрывает печать, публикуя фактическое сообщение (обычно в виде коммисии, например, хэша);
- Он также предоставляет свидетель (криптографическое доказательство), подтверждающий, что печать является закрытой и безотзывной.
Проверка герметичности :
- Как только печать закрыта, Боб уже не может ее открыть: он может только проверить, что она закрыта;
- Боб собирает печать, свидетеля и сообщение (или свое обязательство), чтобы убедиться, что все совпадает и что нет конкурирующих печатей или различных версий.
Вкратце этот процесс можно описать следующим образом:
# Défini par Alice, validé ou accepté par Bob
seal <- Define()
# Fermeture du sceau par Alice avec le message
witness <- Close(seal, message)
# Vérification par Bob
bool <- Verify(seal, witness, message)
Однако проверка на стороне клиента идет на шаг дальше: если само определение печати остается за пределами блокчейна, то теоретически кто-то может оспорить существование или легитимность данной печати. Чтобы преодолеть эту проблему, используется цепочка взаимосвязанных одноразовых печатей:
- Каждая закрытая печать содержит определение следующей печати;
- Мы регистрируем эти закрытия (с их коммитментами) в блокчейне (в транзакции Bitcoin);
- Таким образом, любая попытка изменить предыдущую печать будет противоречить истории, заложенной в Биткойне.
Именно это и делает система RGB:
- Опубликованные сообщения - это обязательства по проверке данных на стороне клиента;
- Определение печати связано с Bitcoin UTXO;
- Печать закрывается, когда этот UTXO израсходован или когда на это же обязательство начисляется новый выход;
- Цепочка транзакций, которая расходует эти UTXO, соответствует доказательству публикации: каждый переход или изменение состояния RGB, таким образом, закрепляется в Bitcoin.
Подведем итоги:
- Определение печати - это UTXO, которым вы собираетесь запечатать будущее обязательство;
- Закрытие печати происходит, когда вы тратите этот UTXO, создавая транзакцию, содержащую обязательство;
- Свидетелем_ является сама сделка, которая доказывает, что вы закрыли печать с таким содержанием;
- Вы не можете доказать, что печать не была закрыта (вы не можете быть абсолютно уверены, что UTXO не был потрачен или не будет потрачен в блоке, который вы еще не видели), но вы можете доказать, что она действительно была закрыта.
Эта уникальность важна для валидации на стороне клиента: когда вы валидируете переход состояния, вы проверяете, что он соответствует уникальному UTXO, не потраченному ранее в конкурирующем обязательстве. Именно это гарантирует отсутствие двойных трат во внецепочечных смарт-контрактах.
Многочисленные обязательства и корни
Смарт-контракту RGB может потребоваться потратить несколько одноразовых печатей (несколько UTXO) одновременно. Более того, одна транзакция Биткойна может ссылаться на несколько разных контрактов, каждый из которых запечатывает свой собственный переход состояния. Это требует наличия механизма многокомпонентности для детерминированного и однозначного доказательства того, что ни один из контрактов не существует в двух экземплярах. Именно здесь в RGB вступает в игру понятие якоря: специальная структура, связывающая транзакцию Bitcoin и одно или несколько клиентских обязательств (переходов состояний), каждое из которых потенциально может принадлежать отдельному контракту. Мы подробнее рассмотрим эту концепцию в следующей главе.
В двух основных репозиториях проекта на GitHub (под организацией LNPBP) собраны базовые реализации этих концепций, изученных в первой главе:
- client_side_validation** : Содержит примитивы Rust для локальной проверки;
- single_use_seals**: Реализует логику для определения и безопасного закрытия этих печатей.
Обратите внимание, что эти программные кирпичики не зависят от Биткойна; теоретически их можно применить к любому другому средству подтверждения публикации (другому реестру, журналу и т. д.). На практике RGB полагается на биткойн благодаря его надежности и широкому консенсусу.
Вопросы от общественности
На пути к более широкому использованию одноразовых уплотнений
Питер Тодд также создал протокол Open Timestamps, и концепция одноразовых печатей является естественным продолжением этих идей. Помимо RGB, можно предусмотреть и другие варианты использования, например, построение сайдчейнов без использования мерж-майнинга или предложения, связанные с драйвчейнами, такие как BIP300. Любая система, требующая единичного обязательства, в принципе может использовать этот криптографический примитив. Сегодня RGB является первой крупной полномасштабной реализацией.
Проблемы с доступностью данных
Поскольку при проверке на стороне клиента каждый пользователь хранит свою часть истории, доступность данных в глобальном масштабе не гарантируется. Если эмитент контракта утаивает или отзывает определенную информацию, вы можете не знать о фактическом развитии предложения. В некоторых случаях (например, в случае со стабильными монетами) ожидается, что эмитент будет поддерживать публичные данные для подтверждения объема, находящегося в обращении, но технического обязательства делать это не существует. Поэтому можно разработать заведомо непрозрачные контракты с неограниченным предложением, что ставит вопрос о доверии.
Шардинг и изоляция контрактов
Каждый контракт представляет собой изолированный осколок: USDT и USDC, например, не обязаны делиться своими историями. Атомарные обмены по-прежнему возможны, но это не предполагает слияния их реестров. Все делается с помощью криптографических обязательств, без раскрытия всего графа истории каждому участнику.
Заключение
Мы уже видели, как концепция Client-side Validation сочетается с блокчейном и государственными каналами, как она отвечает на трилеммы распределенных вычислений и как она уникально использует блокчейн Биткойна для предотвращения двойных трат и для временного клеймения. Идея основана на понятии Пломба одноразового использования, позволяющем создавать уникальные обязательства, которые нельзя повторно расходовать по своему усмотрению. Таким образом, каждый участник загружает только ту историю, которая строго необходима, что повышает масштабируемость и конфиденциальность смарт-контрактов, сохраняя при этом безопасность Биткойна как основы.
Следующим шагом будет более подробное объяснение того, как этот механизм одноразовых печатей применяется в Биткойне (через UTXO), как создаются и проверяются якоря, а затем как строятся полные смарт-контракты в RGB. В частности, мы рассмотрим проблему множественных обязательств - техническую задачу доказательства того, что транзакция Bitcoin одновременно запечатывает несколько переходов состояний в разных контрактах, не создавая при этом уязвимостей или двойных обязательств.
Прежде чем погрузиться в технические детали второй главы, перечитайте ключевые определения (Client-side Validation, Single-use Seal, anchors и т. д.) и запомните общую логику: мы стремимся совместить сильные стороны блокчейна биткоина (безопасность, децентрализацию, временную маркировку) с сильными сторонами внецепочечных решений (скорость, конфиденциальность, масштабируемость), и именно этого пытаются добиться RGB и Client-side Validation.
Слой обязательств
В этой главе мы рассмотрим реализацию клиентской валидации и одноразовых печатей в блокчейне Биткойна. Мы представим основные принципы работы уровня коммитмента (уровень 1) RGB, уделив особое внимание схеме TxO2, которую RGB использует для определения и закрытия печати в транзакции Bitcoin. Далее мы обсудим два важных момента, которые еще не были подробно рассмотрены:
- Детерминированные обязательства биткоина;
- Многопротокольные обязательства.
Именно сочетание этих концепций позволяет накладывать несколько систем или контрактов поверх одного UTXO и, соответственно, одного блокчейна.
Следует помнить, что описанные криптографические операции в абсолютном смысле могут быть применены и к другим блокчейнам или средствам публикации, но характеристики Биткойна (децентрализация, устойчивость к цензуре и открытость для всех) делают его идеальной основой для разработки расширенных возможностей программирования, таких как те, что требуются RGB.
Схемы фиксации в Биткойне и их использование в RGB
Как мы видели в первой главе курса, одноразовые печати - это общая концепция: мы даем обещание включить обязательство (commitment) в определенное место транзакции, и это место действует как печать, которую мы закрываем на сообщении. Однако в блокчейне Биткойна есть несколько вариантов выбора места для размещения этого обязательства.
Чтобы понять логику, давайте вспомним основной принцип: чтобы закрыть одноразовую печать, мы расходуем запечатанную область, вставляя коммитмент на данное сообщение. В Биткойне это можно сделать несколькими способами:
- Используйте открытый ключ или адрес**
Мы можем решить, что определенный открытый ключ или адрес является одноразовой печатью. Как только этот ключ или адрес появляется на цепочке в транзакции, это означает, что печать закрыта определенным сообщением.
- Используйте вывод транзакций Bitcoin**
Это означает, что одноразовая пломба определяется как точная точка выхода (пара TXID + номер выхода). Как только эта выходная точка будет израсходована, пломба будет закрыта.
Работая над RGB, мы выявили как минимум 4 различных способа реализации этих печатей в Bitcoin:
- Определите печать через открытый ключ и закройте ее в выходе ;
- Определите печать с помощью outpoint и закройте ее с помощью output ;
- Определите печать через значение открытого ключа и закройте ее в входе ;
- Определите печать через outpoint, а закройте ее через input.
| Название схемы | Определение пломбы | Закрытие пломбы | Дополнительные требования | Основное применение | Возможные схемы обязательств |
|---|---|---|---|---|---|
| PkO | Значение открытого ключа | Выход транзакции | P2(W)PKH | Пока нет | Keytweak, taptweak, opret |
| TxO2 | Выход транзакции | Выход транзакции | Требует детерминированных обязательств на Bitcoin | RGBv1 (универсальный) | Keytweak, tapret, opret |
| PkI | Значение открытого ключа | Вход транзакции | Только Taproot & несовместимо с устаревшими кошельками | Идентификация на базе Bitcoin | Sigtweak, witweak |
| TxO1 | Выход транзакции | Вход транзакции | Только Taproot & несовместимо с устаревшими кошельками | Пока нет | Sigtweak, witweak |
Мы не будем подробно останавливаться на каждой из этих конфигураций, поскольку в RGB мы решили использовать аутпоинт_ в качестве определения печати, а коммитмент поместить в выход транзакции, расходующей этот аутпоинт. Поэтому мы можем ввести следующие понятия для продолжения:
- "Определение пломбы "** : Данная выходная точка (идентифицируется TXID + номер выхода) ;
- "Закрытие печати "**: Транзакция, которая проводит эту outpoint, в которой commitment добавляется к сообщению.
Эта схема была выбрана из-за ее совместимости с архитектурой RGB, но другие конфигурации могут быть полезны для различных целей.
Буква "O2" в слове "TxO2" напоминает нам о том, что и определение, и закрытие основаны на расходовании (или создании) транзакционного вывода.
Пример диаграммы TxO2
Напомним, что определение одноразовой печати не обязательно требует публикации транзакции на цепи. Достаточно, чтобы у Алисы, например, уже был неизрасходованный UTXO. Она может решить: "Этот outpoint (уже существующий) теперь будет моей печатью". Она отмечает это локально (со стороны клиента), и до тех пор, пока этот UTXO не будет потрачен, печать считается открытой.
В день, когда он хочет закрыть печать (чтобы сигнализировать о событии или закрепить конкретное сообщение), он тратит этот UTXO в новой транзакции (эту транзакцию часто называют "свидетельской транзакцией" (не связанной с сегвитом, это просто термин, который мы ему дали). Эта новая транзакция будет содержать коммитмент к сообщению.
Обратите внимание, что в этом примере :
- Никто, кроме Боба (или людей, которым Алиса решит раскрыть полное доказательство), не будет знать, что в этой транзакции скрыто определенное сообщение;
- Все видят, что вывод был потрачен, но только Боб владеет доказательством того, что сообщение действительно закреплено в транзакции.
Чтобы проиллюстрировать эту схему TxO2, мы можем использовать одноразовую печать в качестве механизма отзыва ключа PGP. Вместо того чтобы публиковать сертификат отзыва на серверах, Алиса может сказать: "Этот вывод биткойнов, если он будет потрачен, означает, что мой PGP-ключ отозван".
Таким образом, у Алисы есть конкретный UTXO, с которым локально (на стороне клиента) связано определенное состояние или данные (известные только ей).
Алиса сообщает Бобу, что если эти UTXO будут потрачены, то будет считаться, что произошло определенное событие. Со стороны мы видим лишь транзакцию Bitcoin, но Боб знает, что эта трата имеет скрытый смысл.
Когда Алиса тратит этот UTXO, она закрывает печать на сообщении, указывающем на ее новый ключ или просто на отзыв старого. Таким образом, все, кто следит за цепочкой, увидят, что UTXO потрачен, но только те, кто имеет полное доказательство, будут знать, что это именно отзыв ключа PGP.
Чтобы Боб или любой другой участник мог проверить скрытое сообщение, Алиса должна предоставить ему информацию вне цепи.
Поэтому Алиса должна предоставить Бобу :
- Само сообщение (например, новый ключ PGP) ;
- Криптографическое доказательство того, что сообщение участвовало в транзакции (известное как доказательство дополнительной транзакции или якорь).
У третьих лиц нет такой информации. Они видят только, что UTXO был потрачен. Таким образом, обеспечивается конфиденциальность.
Чтобы прояснить структуру, представим процесс в виде двух транзакций:
- Транзакция 1**: Здесь содержится определение пломбы, т. е. точка выхода, которая будет служить пломбой.
- Транзакция 2**: Расходует эту outpoint. Это закрывает печать и в той же транзакции вставляет коммитмент на сообщение.
Поэтому мы называем вторую сделку "сделкой свидетеля".
Чтобы проиллюстрировать это с другой стороны, мы можем представить два слоя:
- Верхний уровень (блокчейн, публичный)**: все видят транзакцию и знают, что был потрачен аутпоинт;
- Нижний уровень (на стороне клиента, приватный)**: только Алиса (или заинтересованное лицо) знает, что этот расход соответствует такому-то и такому-то сообщению, через криптографическое доказательство и сообщение, которое она хранит локально.
Но при закрытии печати возникает вопрос, куда вставлять обязательство
В предыдущем разделе мы вкратце рассказали о том, как модель проверки на стороне клиента может быть применена к RGB и другим системам. Здесь мы рассмотрим часть, посвященную детерминированным обязательствам Биткойна и тому, как интегрировать их в транзакцию. Идея заключается в том, чтобы понять, почему мы пытаемся вставить одно обязательство в свидетельскую транзакцию, и, прежде всего, как гарантировать, что не может быть других нераскрытых конкурирующих обязательств.
Места обязательств в сделке
Когда вы предоставляете кому-то доказательство того, что в транзакцию встроено определенное сообщение, вы должны быть в состоянии гарантировать, что в той же транзакции нет другой формы обязательств (второго, скрытого сообщения), которая не была бы вам раскрыта. Чтобы проверка на стороне клиента оставалась надежной, вам нужен детерминированный механизм для размещения единственного обязательства в транзакции, которое закрывает одноразовую печать.
Транзакция свидетель тратит знаменитый UTXO (или определение печати), и эта трата соответствует закрытию печати. Технически говоря, мы знаем, что каждый аутпоинт может быть потрачен только один раз. Именно на этом основана устойчивость биткойна к двойным тратам. Но транзакция по расходованию средств может иметь несколько входов, несколько выходов или быть составлена сложным образом (coinjoins, Lightning channels и т. д.). Поэтому нам нужно четко определить, куда вставлять обязательство в этой структуре, однозначно и единообразно.
Независимо от метода (PkO, TxO2 и т.д.), обязательство может быть вставлено:
- Входе** через :
- Sigtweak** (изменяет
rкомпонент подписи ECDSA, аналогично принципу "Sign-to-contract") ; - Witweak** (данные сегрегированного свидетеля транзакции изменены).
- Sigtweak** (изменяет
- В выходе** через :
- Keytweak** (открытый ключ получателя "подстраивается" под сообщение) ;
- Opret** (сообщение помещается в нерасходуемый выход
OP_RETURN) ; - Tapret** (или Taptweak), который полагается на taproot для вставки обязательств в скриптовую часть ключа taproot, таким образом детерминированно изменяя открытый ключ.
Вот подробное описание каждого метода:
Сигнализация (подписка к контракту) :
Более ранняя схема предполагала использование случайной части подписи (ECDSA или Schnorr) для встраивания обязательства: эта техника известна как "Подпись к контракту". Вы заменяете случайно сгенерированный nonce на хэш, содержащий данные. Таким образом, подпись неявно раскрывает ваши обязательства, не занимая дополнительного места в транзакции. Этот подход имеет ряд преимуществ:
- Нет перегрузки на цепочке (вы используете то же место, что и основной nonce);
- Теоретически это может быть достаточно дискретно, так как nonce изначально является случайной величиной.
Однако выявились два основных недостатка:
- Multisig перед Taproot: когда у вас есть несколько подписантов, вам нужно решить, какая подпись будет нести обязательство. Подписи могут быть расставлены по-разному, и если подписант отказывается, вы теряете контроль над результатом обязательства;
- MuSig и общий нонс: в мультисигме Шнорра (MuSig) генерация нонса является многопартийным алгоритмом, и подстроить нонс по отдельности становится практически невозможно.
На практике sig tweak также не очень совместим с существующим оборудованием (аппаратными кошельками) и форматами (Lightning и т. д.). Так что эту замечательную идею трудно реализовать на практике.
Ключевой твик (оплата по контракту) :
В key tweak используется историческая концепция pay-to-contract. Мы берем открытый ключ X и изменяем
его, добавляя значение H(message). В частности, если X = x * G и h = H(message), то новый ключ будет X' = X + h * G. Этот модифицированный ключ скрывает
приверженность к сообщению. Владелец оригинального закрытого
ключа может, добавив h к своему закрытому ключу x,
доказать, что у него есть ключ для расходования выходных данных. В теории
это элегантно, потому что :
- Ввод обязательства осуществляется без добавления дополнительных полей;
- Вы не храните никаких дополнительных данных на цепочке.
Однако на практике мы сталкиваемся со следующими трудностями:
- Кошельки больше не распознают стандартный открытый ключ, поскольку он был "подправлен", поэтому они не могут легко связать UTXO с вашим обычным ключом;
- Аппаратные кошельки не предназначены для подписи ключом, который не является производным от их стандартного производного;
- Вам нужно адаптировать свои скрипты, дескрипторы и т.д.
В контексте RGB этот путь был предусмотрен до 2021 года, но оказалось, что его слишком сложно реализовать с помощью существующих стандартов и инфраструктуры.
Свидетельский твик :
Другая идея, которую реализовали некоторые протоколы, такие как inscriptions Ordinals, заключается в том, чтобы помещать данные непосредственно в свидетельский раздел транзакции (отсюда выражение "witness tweak").
Однако этот метод :
- Делает взаимодействие сразу видимым (вы буквально вставляете исходные данные в свидетеля);
- Может подвергаться цензуре (майнеры или узлы могут отказать в ретрансляции, если она слишком велика или имеет любую другую произвольную характеристику);
- Занимает много места в блоках, что противоречит цели RGB - свободе и легкости.
Кроме того, witness разработан таким образом, что в определенных контекстах его можно обрезать, что может усложнить получение надежных доказательств.
Открытие-возврат (opret) :
Очень простой по своей работе, OP_RETURN позволяет хранить хэш
или сообщение в специальном поле транзакции. Но это сразу же обнаруживается:
все видят, что в транзакции есть коммитмент, и он может быть
отцензурирован или отброшен, а также добавить дополнительный вывод.
Поскольку это увеличивает прозрачность и размер, с точки зрения решения для
проверки на стороне клиента это считается менее удовлетворительным.
34-byte_Opret_Commitment =
OP_RETURN OP_PUSHBYTE_32 <mpc::Commitment>
|_________| |______________| |_________________|
1-byte 1-byte 32 bytes
Tapret
Последний вариант - использование Taproot (представленного
в BIP341) со схемой Tapret. Tapret - это более сложная
форма детерминированного обязательства, которая дает улучшения в плане следа
на блокчейне и конфиденциальности операций с контрактами. Основная идея
заключается в том, чтобы скрыть обязательство в части Script Path Spend транзакции taproot transaction.
Прежде чем описывать, как обязательство вставляется в транзакцию taproot, давайте рассмотрим точную форму обязательства, которое должно императивно соответствовать 64-байтовой строке построенной следующим образом:
64-byte_Tapret_Commitment =
OP_RESERVED ... ... .. OP_RESERVED OP_RETURN OP_PUSHBYTE_33 <mpc::Commitment> <Nonce>
|___________________________________| |_________| |______________| |_______________| |______|
OP_RESERVED x 29 times = 29 bytes 1 byte 1 byte 32 bytes 1 byte
|________________________________________________________________| |_________________________|
TAPRET_SCRIPT_COMMITMENT_PREFIX = 31 bytes MPC commitment + NONCE = 33 bytes
- 29 байт
OP_RESERVED, затемOP_RETURN, затемOP_PUSHBYTE_33, образуют 31-байтную часть префикса; - Далее идет 32-байтный коммитмент (обычно это корень Меркла из MPC), к которому мы добавляем 1 байт Nonce (всего 33 байта для этой второй части).
Таким образом, 64-байтный метод Tapret выглядит как Opret, к которому мы приписали 29 байт OP_RESERVED и добавили дополнительный байт в качестве Nonce.
Чтобы сохранить гибкость в плане реализации, конфиденциальности и масштабирования, схема Tapret учитывает различные варианты использования в зависимости от требований:
- Уникальное включение обязательства Tapret в сделку taproot без существующей структуры Script Path;
- Интеграция обязательства Tapret в транзакцию Taproot, уже оснащенную Script Path.
Давайте рассмотрим каждый из этих двух сценариев подробнее.
Регистрация Tapret без существующего Script Path
В этом первом случае мы начинаем с выходного ключа тапроота (Taproot Output Key) Q, который содержит только внутренний открытый ключ P (Internal Key), без связанного с ним пути сценария (Script Path):
P: внутренний открытый ключ для Key Path Spend.G: порождающая точка эллиптической кривой secp256k1.- t = tH_TWEAK(P)
- коэффициент твика, вычисляемый через _меченый хэш_ (например,SHA-256(SHA-256(TapTweak) || P)`), в соответствии с BIP86. Это доказывает, что скрытого скрипта не существует.
Чтобы включить обязательство Tapret, добавьте Script Path Spend с уникальным сценарием, как показано ниже:
- t = tH_TWEAK(P || Script_root)` становится новым фактором твика, включая Script_root.
Script_root = tH_BRANCH(64-byte_Tapret_Commitment)представляет корень этого скрипта, который является просто хэшем типаSHA-256(SHA-256(TapBranch) || 64-byte_Tapret_Commitment).
Доказательство включения и уникальности в корневом дереве здесь сводится к
единственному внутреннему открытому ключу P.
Интеграция Tapret в уже существующий Script Path
Второй сценарий касается более сложного вывода Q taproot**, который
уже содержит несколько скриптов. Например, у нас есть дерево из 3 сценариев:
- tH_LEAF(x)` обозначает нормализованную тегированную хэш-функцию скрипта листа.
- a, B, C` представляют скрипты, уже включенные в структуру корня.
Чтобы добавить обязательство Тапрета, нам нужно вставить нерастрачиваемый скрипт на первый уровень дерева, сместив существующие скрипты на один уровень вниз. Визуально дерево становится :
- tHABC
представляет собой тегированный хэш группировки верхнего уровняA, B, C`. - tHT
представляет собой хэш скрипта, соответствующий 64-байтовомуTapret`.
Согласно правилам taproot, каждая ветвь/лист должна быть объединена в соответствии с лексикографическим хэш-порядком. Возможны два случая:
tHT>tHABC: обязательство Тапрета перемещается в правую часть дерева. Для доказательства единственности нужны толькоtHABCиP;- tHT
<tHABC**: обязательство Тапрета расположено слева. Чтобы доказать, что справа нет другого обязательства Тапрета, необходимо раскрытьtHABиtHC`, чтобы продемонстрировать отсутствие любого другого такого сценария.
Визуальный пример для первого случая (tHABC < tHT):
Пример для второго случая (tHABC > tHT):
Оптимизация с помощью ключа
Для повышения конфиденциальности мы можем "добыть" (более точным термином
будет "перебор") значение <Nonce> (последний байт
64-байтового Tapret) в попытке получить хэш tHT такой, что tHABC < tHT. В этом случае обязательство
возлагается на правую сторону, избавляя пользователя от необходимости
разглашать все содержимое существующих скриптов для доказательства
уникальности Tapret.
В целом, Tapret предлагает дискретный и детерминированный способ
включения обязательства в транзакцию taproot, соблюдая при этом требования уникальности
и однозначности, необходимые для логики проверки на стороне клиента и одноразовых
печатей RGB.
Действительные выходы
Для транзакций с обязательствами RGB основное требование к действительной схеме обязательств Биткойна заключается в следующем: Транзакция (транзакция-свидетель) должна доказательно содержать одно обязательство. Это требование делает невозможным построение альтернативной истории для подтвержденных данных на стороне клиента в рамках одной транзакции. Это означает, что сообщение, вокруг которого закрывается одноразовая печать, является уникальным.
Чтобы удовлетворить этому принципу, независимо от количества выходов в транзакции, мы требуем, чтобы один и только один выход содержал обязательство (commitment). Для каждой из используемых схем (Opret или Tapret) единственными допустимыми выходами, которые могут содержать RGB commitment, являются :
- Первый выходной
OP_RETURN(если он присутствует) для схемы Opret; - Первый вывод taproot (если он есть) для схемы Tapret.
Обратите внимание, что вполне возможно, что транзакция будет содержать одно
обязательство Opret и одно обязательство Tapret в двух
отдельных выходах. Благодаря детерминированному характеру Seal Definition эти
два обязательства соответствуют двум различным частям данных, подтвержденных
на стороне клиента.
Анализ и практический выбор в RGB
Когда мы создавали RGB, мы рассмотрели все эти методы, чтобы определить, где и как детерминированно разместить коммитмент в транзакции. Мы определили некоторые критерии:
- Совместимость с различными сценариями (например, multisig, Lightning, аппаратные кошельки и т. д.);
- Влияние на пространство цепочки ;
- Сложность внедрения и обслуживания;
- Конфиденциальность и сопротивление цензуре.
| Метод | След и размер в блокчейне | Размер на стороне клиента | Интеграция кошельков | Аппаратная совместимость | Совместимость с Lightning | Совместимость с Taproot |
|---|---|---|---|---|---|---|
| Keytweak (детерминированный P2C) | 🟢 | 🟡 | 🔴 | 🟠 | 🔴 BOLT, 🔴 Bifrost | 🟠 Taproot, 🟢 MuSig |
| Sigtweak (детерминированный S2C) | 🟢 | 🟢 | 🟠 | 🔴 | 🔴 BOLT, 🔴 Bifrost | 🟠 Taproot, 🔴 MuSig |
| Opret (OP_RETURN) | 🔴 | 🟢 | 🟢 | 🟠 | 🔴 BOLT, 🟠 Bifrost | - |
| Алгоритм Tapret: верхний левый узел | 🟠 | 🔴 | 🟠 | 🟢 | 🔴 BOLT, 🟢 Bifrost | 🟢 Taproot, 🟢 MuSig |
| Алгоритм Tapret # 4: любой узел + доказательство | 🟢 | 🟠 | 🟠 | 🟢 | 🔴 BOLT, 🟢 Bifrost | 🟢 Taproot, 🟢 MuSig |
| Детерминированная схема обязательств | Стандарт | Затраты в блокчейне | Размер доказательства на стороне клиента |
|---|---|---|---|
| Keytweak (детерминированный P2C) | LNPBP-1, 2 | 0 байт | 33 байта (некорректированный ключ) |
| Sigtweak (детерминированный S2C) | WIP (LNPBP-39) | 0 байт | 0 байт |
| Opret (OP_RETURN) | - | 36 (v)байт (дополнительный TxOut) | 0 байт |
| Алгоритм Tapret: верхний левый узел | LNPBP-6 | 32 байта в свидетельстве (8 vбайт) для любого n-of-m мультиподписи и расходов через путь скрипта | 0 байт для scriptless scripts taproot ~270 байт в случае одного скрипта, ~128 байт, если несколько скриптов |
| Алгоритм Tapret #4: любой узел + доказательство уникальности | LNPBP-6 | 32 байта в свидетельстве (8 vбайт) для случаев с одним скриптом, 0 байт в свидетельстве в большинстве других случаев | 0 байт для scriptless scripts taproot, 65 байт, пока Taptree не содержит дюжину скриптов |
| Уровень | Затраты on-chain (bytes/vbytes) | Затраты on-chain (bytes/vbytes) | Затраты on-chain (bytes/vbytes) | Затраты on-chain (bytes/vbytes) | Затраты on-chain (bytes/vbytes) | Затраты на клиенте (bytes) | Затраты на клиенте (bytes) | Затраты на клиенте (bytes) | Затраты на клиенте (bytes) | Затраты на клиенте (bytes) |
|---|---|---|---|---|---|---|---|---|---|---|
| Тип | Tapret | Tapret #4 | Keytweak | Sigtweak | Opret | Tapret | Tapret #4 | Keytweak | Sigtweak | Opret |
| Single-sig | 0 | 0 | 0 | 0 | 32 | 0 | 0 | 32 | 0? | 0 |
| MuSig (n-of-n) | 0 | 0 | 0 | 0 | 32 | 0 | 0 | 32 | ? > 0 | 0 |
| Multi-sig 2-of-3 | 32/8 | 32/8 или 0 | 0 | n/a | 32 | ~270 | 65 | 32 | n/a | 0 |
| Multi-sig 3-of-5 | 32/8 | 32/8 или 0 | 0 | n/a | 32 | ~340 | 65 | 32 | n/a | 0 |
| Multi-sig 2-of-3 с таймаутами | 32/8 | 0 | 0 | n/a | 32 | 64 | 65 | 32 | n/a | 0 |
| Уровень | Затраты on-chain (vbytes) | Затраты on-chain (vbytes) | Затраты on-chain (vbytes) | Клиентские затраты (bytes) | Клиентские затраты (bytes) |
|---|---|---|---|---|---|
| Тип | База | Tapret #2 | Tapret #4 | Tapret #2 | Tapret #4 |
| MuSig (n-of-n) | 16.5 | 0 | 0 | 0 | 0 |
| FROST (n-of-m) | ? | 0 | 0 | 0 | 0 |
| Multi_a (n-of-m) | 1+16n+8m | 8 | 8 | 33 * m | 65 |
| Ветка MuSig / Multi_a (n-of-m) | 1+16n+8n+8xlog(n) | 8 | 0 | 64 | 65 |
| С тайм-аутами (n-of-m) | 1+16n+8n+8xlog(n) | 8 | 0 | 64 | 65 |
| Метод | Конфиденциальность и Масштабируемость | Интероперабельность | Совместимость | Переносимость | Сложность |
|---|---|---|---|---|---|
| Keytweak (детерминированный P2C) | 🟢 | 🔴 | 🔴 | 🟡 | 🟡 |
| Sigtweak (детерминированный S2C) | 🟢 | 🔴 | 🔴 | 🟢 | 🔴 |
| Opret (OP_RETURN) | 🔴 | 🟠 | 🔴 | 🟢 | 🟢 |
| Algo Tapret: верхний левый узел | 🟠 | 🟢 | 🟢 | 🔴 | 🟠 |
| Algo Tapret #4: Любой узел + доказательство | 🟢 | 🟢 | 🟢 | 🟠 | 🔴 |
В ходе исследования стало ясно, что ни одна из схем обязательств не является полностью совместимой с текущим стандартом Lightning (в котором не используются Taproot, muSig2 или дополнительная поддержка обязательств). В настоящее время ведутся работы по изменению конструкции канала Lightning (BiFrost), чтобы позволить вставлять RGB-обязательства. Это еще одна область, в которой нам необходимо пересмотреть структуру транзакций, ключи и способ подписи обновлений канала.
Анализ показал, что на самом деле другие методы (key tweak, sig tweak, witness tweak и т. д.) дают другие формы осложнений:
- Либо у нас большой объем цепочки;
- Либо существует радикальная несовместимость с существующим кодом кошелька;
- Либо решение нежизнеспособно в некооперативной мультисигме.
Для RGB особенно выделяются два метода: Opret и Tapret, оба классифицируются как "Транзакционный выход" и совместимы с режимом TxO2, используемым в протоколе.
Мультипротокольные обязательства - MPC
В этом разделе мы рассмотрим, как RGB обрабатывает
агрегирование нескольких контрактов (или, точнее, их пучков переходов) в рамках одного обязательства (commitment), записанного в транзакции Биткойна по детерминированной схеме (согласно Opret или Tapret). Для этого порядок меркелизации различных
контрактов происходит в структуре, называемой MPC Tree (Multi Protocol Commitment Tree). В этом разделе мы рассмотрим, как построить это дерево MPC, как получить
его корень и как несколько контрактов могут конфиденциально и однозначно
передавать одну и ту же транзакцию.
Multi Protocol Commitment (MPC) предназначен для удовлетворения двух потребностей:
- Построение хэша
mpc::Commitment: он будет включен в блокчейн Биткойна по схемеOpretилиTapretи должен отражать все изменения состояния, подлежащие проверке; - Одновременное хранение нескольких контрактов в одном коммитменте, что позволяет управлять отдельными обновлениями нескольких активов или контрактов RGB в одной транзакции Биткойна.
Говоря конкретнее, каждый пучок переходов принадлежит определенному
контракту. Вся эта информация вставляется в MPC-дерево,
корень которого (mpc::Root) затем снова хэшируется, чтобы
получить mpc::Commitment. Именно этот последний хэш помещается
в транзакцию Биткойна (свидетельскую транзакцию) в соответствии с
выбранным детерминированным методом.
Корневой хэш MPC
Значение, фактически записанное на цепочке (в Opret или Tapret), называется mpc::Commitment. Оно
вычисляется в форме BIP-341 по формуле :
mpc::Commitment = SHA-256(SHA-256(mpc_tag) || SHA-256(mpc_tag) || depth || cofactor || mpc::Root )
где :
mpc_tag- это тег:urn:ubideco:mpc:commitment#2024-01-31, выбранный в соответствии с [RGB tagging conventions] (https://github.com/RGB-WG/rgb-core/blob/master/doc/Commitments.md);depth(1 байт) указывает глубину MPC-дерева ;- cofactor` (16 бит, в Little Endian) - параметр, используемый для повышения уникальности позиций, присвоенных каждому контракту в дереве;
mpc::Root- это корень MPC Tree, вычисляемый в соответствии с процессом, описанным в следующем разделе.
MPC Строительство деревьев
Чтобы построить это дерево MPC, нам нужно убедиться, что каждый контракт соответствует уникальной позиции листа. Предположим, что у нас есть :
- c
контрактов, которые должны быть включены, индексируемыеiвi = {0,1,...,C-1}` ; - Для каждого контракта
c_iу нас есть идентификаторContractId(i) = c_i.
Затем мы строим дерево шириной w и глубиной d,
такое, что 2^d = w, причем w > C, так что каждый
контракт может быть помещен в отдельный лист. Позиция pos(c_i) каждого контракта в дереве определяется :
pos(c_i) = c_i mod (w - cofactor)
где кофактор - целое число, увеличивающее вероятность получения
разных позиций для каждого контракта. На практике построение происходит итерационно:
- Мы начинаем с минимальной глубины (условно
d=3, чтобы скрыть точное количество контрактов); - Мы пробуем различные
коэффициенты(вплоть доw/2, или максимум 500 по соображениям производительности); - Если нам не удается расположить все контракты без столкновений, мы
увеличиваем
dи начинаем сначала.
Задача состоит в том, чтобы избегать слишком высоких деревьев и при этом свести риск столкновения к минимуму. Обратите внимание, что явление столкновения подчиняется логике случайного распределения, связанной с Парадоксом Юбилея.
Обитаемые листья
После того как для контрактов i = {0,1,...,C-1} было
получено C различных позиций pos(c_i), каждый лист
заполняется хэш-функцией (tagged hash):
tH_MPC_LEAF(c_i) = SHA-256(SHA-256(merkle_tag) || SHA-256(merkle_tag) || 0x10 || c_i || BundleId(c_i))
где :
merkle_tag = urn:ubideco:merkle:node#2024-01-31, всегда выбирается в соответствии с конвенциями Меркла для RGB;0x10идентифицирует контрактный лист ;c_i- 32-байтовый идентификатор контракта (полученный из хэша Genesis);- bundleId(c_i)
- 32-байтовый хэш, описывающий наборпереходов состоянийотносительноc_i` (собранных в пакет переходов).
Необитаемые листья
Оставшиеся листья, которым не присвоен контракт (т.е. листья w - C), заполняются "фиктивным" значением (энтропийный лист):
tH_MPC_LEAF(j) = SHA-256(SHA-256(merkle_tag) || SHA-256(merkle_tag) || 0x11 || entropy || j )
где :
merkle_tag = urn:ubideco:merkle:node#2024-01-31, всегда выбирается в соответствии с конвенциями Меркла для RGB;0x11обозначает энтропийный лист ;энтропия- это случайное значение размером 64 байта, выбранное человеком, строящим дерево;j- это позиция (в 32 битах Little Endian) данного листа в дереве.
Узлы MPC
После генерации листьев w (заселенных или нет) мы переходим к меркелизации.
Все внутренние узлы хэшируются следующим образом:
tH_MPC_BRANCH(tH1 || tH2) = SHA-256(SHA-256(merkle_tag) || SHA-256(merkle_tag) || b || d || w || tH1 || tH2)
где :
merkle_tag = urn:ubideco:merkle:node#2024-01-31, всегда выбирается в соответствии с конвенциями Меркла для RGB;- b
- это _коэффициент разветвления_ (8 бит). Чаще всегоb=0x02`, поскольку дерево является бинарным и полным; - d` - глубина узла в дереве;
w- ширина дерева (в 256-битном двоичном формате Little Endian);- tH1
иtH2` - это хэши дочерних узлов (или листьев), уже вычисленные, как показано выше.
Продвигаясь таким образом, мы получаем корень mpc::Root. Затем
мы можем вычислить mpc::Commitment (как объяснялось выше) и вставить
его в цепочку.
Чтобы проиллюстрировать это, давайте представим пример, в котором C=3 (три контракта). Их позиции принимаются равными pos(c_0)=7, pos(c_1)=4, pos(c_2)=2. Остальные листья (позиции
0, 1, 3, 5, 6) - это энтропийные листья. На диаграмме ниже показана
последовательность хэшей к корню с :
BUNDLE_i, который представляет собойBundleId(c_i);tH_MPC_LEAF(A)и так далее, которые представляют собой листья (одни для контрактов, другие для энтропии);- Каждая ветвь
tH_MPC_BRANCH(...)объединяет хэши двух своих дочерних ветвей.
В итоге получается mpc::Root, затем mpc::Commitment.
Проверка вала MPC
Когда верификатор хочет убедиться, что контракт c_i (и его BundleId) включен в конечный mpc::Commitment, он
просто получает доказательство Меркла. Это доказательство указывает узлы,
необходимые для отслеживания листьев (в данном случае, листа контракта c_i) обратно к корню. Нет
необходимости раскрывать все MPC-дерево: это защищает
конфиденциальность других контрактов.
В примере верификатору c_2 нужен только промежуточный хэш (tH_MPC_LEAF(D)), два tH_MPC_BRANCH(...), доказательство позиции pos(c_2) и значение cofactor. Затем он может локально восстановить
корень, затем пересчитать mpc::Commitment и сравнить его с тем,
который был записан в транзакции Bitcoin (в рамках Opret или Tapret).
Этот механизм гарантирует, что :
- Статус относительно
c_2действительно включен в блок агрегированной информации (на стороне клиента); - Никто не может построить альтернативную историю с той же транзакцией, потому что цепочка обязательств указывает на один корень MPC.
Краткое описание структуры MPC
Multi Protocol Commitment* (MPC) - это принцип, позволяющий RGB объединять несколько контрактов в одну транзакцию Bitcoin, сохраняя уникальность обязательств и конфиденциальность по отношению к другим участникам. Благодаря детерминированному построению дерева, каждому контракту присваивается уникальная позиция, а наличие "фиктивных" листьев (Entropy Leaves) частично маскирует общее количество контрактов, участвующих в транзакции.
Все дерево Меркла никогда не хранится на клиенте. Мы просто генерируем путь Меркла для каждого соответствующего контракта, который передается получателю (который затем может подтвердить обязательство). В некоторых случаях у вас может быть несколько активов, которые прошли через один и тот же UTXO. Тогда вы можете объединить несколько меркл-путей в так называемый мультипротокольный блок обязательств, чтобы избежать дублирования большого количества данных.
Поэтому каждое доказательство Меркла является легким, тем более что глубина дерева не превышает 32 в RGB. Существует также понятие "блок Меркла", в котором сохраняется больше информации (сечение, энтропия и т. д.), полезной для объединения или разделения нескольких ветвей.
Именно поэтому работа над RGB заняла так много времени. У нас было общее видение с 2019 года: разместить все на стороне клиента, циркулировать токены вне цепи. Но такие детали, как шардинг для нескольких контрактов, структура дерева Меркла, способы обработки коллизий и доказательств слияния... все это требовало итераций.
Якоря: глобальная сборка
После создания наших обязательств (Opret или Tapret) и нашего MPC (Multi Protocol Commitment) нам
необходимо рассмотреть понятие Anchor в протоколе RGB.
Якорь - это проверяемая структура на стороне клиента, которая объединяет
элементы, необходимые для проверки того, что обязательство Биткойна
действительно содержит определенную информацию о контракте. Другими словами,
якорь суммирует все данные, необходимые для проверки обязательств,
описанных выше.
Якорь состоит из трех упорядоченных полей:
TxidMPC Proof- дополнительное доказательство транзакции - ЭТП
Каждое из этих полей играет определенную роль в процессе проверки, будь то
реконструкция основной транзакции Bitcoin или доказательство существования
скрытого обязательства (особенно в случае с Tapret).
TxId
Поле Txid соответствует 32-байтовому идентификатору транзакции
Bitcoin, содержащей обязательство Opret или Tapret.
Теоретически, следуя логике одноразовых печатей, можно было бы найти этот Txid, проследив цепочку переходов состояний, которые сами по себе указывают на
каждую транзакцию-свидетеля. Однако для облегчения и ускорения проверки этот Txid просто включается в Anchor, избавляя валидатора от необходимости
просматривать всю историю вне цепочки.
Доказательство MPC
Второе поле, MPC Proof, относится к доказательству того, что
данный конкретный контракт (например, c_i) включен в Multi Protocol Commitment. Оно представляет собой комбинацию из :
pos_i- позиция данного контракта в дереве MPC;- cofactor`, значение, определяемое для разрешения позиционных коллизий;
доказательство Меркла, т.е. набор узлов и хэшей, используемых для восстановления корня MPC и проверки того, что идентификатор контракта и егопакет переходовзафиксированы в корне.
Этот механизм был описан в предыдущем разделе о построении MPC-дерева, где каждый контракт получает уникальный лист благодаря :
pos(c_i) = c_i mod (w - cofactor)
Затем используется детерминированная схема меркелизации для объединения всех
листьев (контракты + энтропия). В конце концов, MPC Proof позволяет локально восстановить корень и сравнить его с mpc::Commitment, включенным в цепочку.
Дополнительное доказательство транзакции - ETP
Третье поле, ETP, зависит от типа используемого
обязательства. Если обязательство имеет тип Opret, то
дополнительного доказательства не требуется. Валидатор проверяет первый
выход транзакции OP_RETURN и находит там непосредственно mpc::Commitment.
Если обязательство имеет тип Tapret, должно
быть предоставлено дополнительное доказательство, называемое Extra Transaction Proof - ETP. Оно содержит :
- Внутренний открытый ключ (
P) вывода taproot, в который встроен коммитмент; - Узлы-партнеры
Script Path Spend(когда Tapret commitment вставляется в скрипт), чтобы доказать точное местоположение этого скрипта в дереве taproot: - Если
Tapretобязательство находится на правой ветви, мы раскрываем левый узел (например,tHABC), - Если обязательство
Tapretнаходится слева, вам нужно раскрыть 2 узла (например,tHABиtHC), чтобы доказать, что в правой части нет другого обязательства. nonceможет использоваться для "добычи" наилучшей конфигурации, позволяя поместить обязательство в правую часть дерева (оптимизация доказательства).
Это дополнительное доказательство необходимо, поскольку, в отличие от Opret, обязательство Tapret интегрировано в структуру скрипта
taproot, что требует раскрытия части дерева taproot, чтобы правильно
подтвердить местоположение обязательства.
Таким образом, Анкоры содержат всю информацию, необходимую
для подтверждения обязательств Биткойна в контексте RGB. Они указывают как
соответствующую транзакцию (Txid), так и доказательство
позиционирования контракта (MPC Proof), управляя дополнительным
доказательством (ETP) в случае Tapret. Таким
образом, якорь защищает целостность и уникальность состояния вне цепи,
гарантируя, что одна и та же транзакция не может быть переинтерпретирована
для других контрактных данных.
Заключение
В этой главе мы рассмотрим :
- Как применить концепцию одноразовых печатей в Биткойне (в частности, через outpoint);
- Различные методы детерминированной вставки коммитмента в транзакцию (Sig tweak, Key tweak, witness tweak, op_return, Taproot/Tapret);
- Причины, по которым RGB фокусируется на обязательствах Тапрета;
- Управление несколькими контрактами с помощью мультипротокольных обязательств, что очень важно, если вы не хотите раскрывать весь штат или другие контракты, когда хотите доказать определенную точку зрения;
- Мы также видели роль Анкоров, которые объединяют все вместе (TXID транзакции, доказательство дерева Меркла и доказательство Taproot) в одном пакете.
На практике техническая реализация разделена между несколькими выделенными Rust crates (в client_side_validation, commit-verify, bp_core и т.д.). Основополагающие понятия там есть:
В следующей главе мы рассмотрим чисто внецепочечный компонент RGB, а именно логику контрактов. Мы увидим, как контракты RGB, организованные как частично реплицируемые бесконечные машины состояний, достигают гораздо большей выразительности, чем биткойн-скрипты, сохраняя при этом конфиденциальность своих данных.
Введение в смарт-контракты и их состояния
В этой и следующей главе мы рассмотрим понятие умного контракта в среде RGB и изучим различные способы, с помощью которых эти контракты могут определять и изменять свое состояние. Мы увидим, почему архитектура RGB, использующая упорядоченную последовательность одноразовых печатей, позволяет выполнять различные типы контрактных операций масштабируемым способом и без прохождения через централизованный реестр. Мы также рассмотрим фундаментальную роль Бизнес-логики в определении эволюции состояния контракта.
Смарт-контракты и цифровые права на предъявителя
Цель RGB - предоставить инфраструктуру для реализации смарт-контрактов на Bitcoin. Под "умным контрактом" мы понимаем соглашение между несколькими сторонами, которое выполняется автоматически и на основе вычислений, без вмешательства человека для обеспечения выполнения его положений. Другими словами, законность договора обеспечивается программным обеспечением, а не доверенной третьей стороной.
Такая автоматизация ставит вопрос о децентрализации: как мы можем освободиться от централизованного реестра (например, центральной платформы или базы данных) для управления правом собственности и исполнения контрактов? Оригинальная идея, подхваченная RGB, заключается в том, чтобы вернуться к способу владения, известному как "инструменты на предъявителя". Исторически сложилось так, что некоторые ценные бумаги (облигации, акции и т. д.) выпускались на предъявителя, что позволяло любому, кто физически владел документом, реализовать свои права.
RGB применяет эту концепцию к цифровому миру: права (и обязательства) заключены в данных, которые манипулируются вне цепи, а статус этих данных подтверждается самими участниками. Это априори обеспечивает гораздо большую степень конфиденциальности и независимости по сравнению с другими подходами, основанными на публичных реестрах.
Введение в смарт-контракт Состояние RGB
Смарт-контракт в RGB можно рассматривать как машину состояний, определяемую :
- Состояние, то есть набор информации, отражающий текущую конфигурацию контракта;
- Бизнес-логика (набор правил), которая описывает, при каких условиях и кем может быть изменено состояние.
Важно понимать, что эти контракты не ограничиваются простой передачей токенов. Они могут воплощать широкий спектр приложений: от традиционных активов (токены, акции, облигации) до более сложных механик (права на использование, коммерческие условия и т. д.). В отличие от других блокчейнов, где код контракта доступен и исполняется всеми, подход RGB разграничивает доступ и знание контракта между участниками ("участники контракта"). Существует несколько ролей:
- Эмитент** или создатель контракта, который определяет генезис контракта и его начальные переменные;
- Стороны, обладающие правами** (собственностью) или другими возможностями принуждения;
- Наблюдатели**, которые потенциально могут видеть определенную информацию, но не могут запускать модификации.
Такое разделение ролей способствует противодействию цензуре, поскольку гарантирует, что только уполномоченные лица могут взаимодействовать с договорным состоянием. Это также дает RGB возможность горизонтального масштабирования: большинство проверок происходит вне блокчейна, и только криптографические якоря (обязательства) записываются в Bitcoin.
Статус и бизнес-логика в RGB
С практической точки зрения, Бизнес-логика контракта принимает форму правил и скриптов, определенных в том, что RGB называет Схемой. Схема кодирует :
- Государственная структура (какие поля являются государственными? Какие поля принадлежат каким сторонам?
- Условия действительности (что должно быть проверено перед авторизацией обновления состояния?) ;
- Полномочия (кто может инициировать переход состояния? Кто может только наблюдать?).
В то же время Контрактное государство часто распадается на две составляющие:
- Глобальное состояние: публичная часть, потенциально наблюдаемая всеми (в зависимости от конфигурации);
- Владельческие государства**: частные части, выделенные владельцам через UTXO, на которые ссылается контрактная логика.
Как мы увидим в следующих главах, любое обновление статуса (Операция контракта) должно быть связано с коммитментом биткойна (через Opret или Tapret) и соответствовать сценариям Бизнес-логики,
чтобы считаться действительным.
Договорные операции: создание и эволюция государства
Во вселенной RGB Операция по контракту - это любое событие, которое изменяет контракт из старого состояния в новое состояние. Эти операции следуют следующей логике:
- Мы принимаем к сведению текущий статус контракта;
- Мы применяем правило или операцию (Переход состояния, Генезис, если это самое первое состояние, или Расширение состояния, если есть публичная валентность для ретриггера);
- Мы закрепляем модификацию с помощью новой коммисии на блокчейне, закрывая одну одноразовую печать и создавая другую;
- Соответствующие правообладатели проверяют локально (на стороне клиента), что переход соответствует схеме и что связанная с ним транзакция Bitcoin зарегистрирована на цепи.
В итоге получается обновленный контракт, теперь уже с другим состоянием. Этот переход не требует, чтобы вся сеть Биткойна была в курсе всех деталей, поскольку в блокчейн записывается только небольшой криптографический отпечаток (commitment). Последовательность печатей одноразового использования предотвращает любые двойные траты или двойное использование состояния.
Цепочка операций: от Бытия до Терминального состояния
Чтобы представить это в перспективе, смарт-контракт RGB начинается с Genesis, самого первого состояния. После этого различные операции контракта следуют одна за другой, образуя DAG (Directed Acyclic Graph) операций:
- Каждый переход основывается на предыдущем состоянии (или нескольких, в случае сходящихся переходов);
- Хронологический порядок гарантируется включением каждого перехода в биткойн-якорь, фиксируемый по времени и не изменяемый благодаря консенсусу с помощью Proof-of-Work;
- Когда больше не выполняется никаких операций, достигается терминальное состояние: самое последнее и полное состояние контракта.
Такая топология DAG (вместо простой линейной цепочки) отражает возможность того, что различные части контракта могут развиваться параллельно, если они не противоречат друг другу. RGB заботится о том, чтобы избежать любых несоответствий путем клиентской проверки каждого участника.
Резюме
Смарт-контракты в RGB представляют собой модель цифровых инструментов на предъявителя, децентрализованных, но привязанных к Bitcoin для фиксации времени и гарантирования порядка транзакций. Автоматизированное выполнение этих контрактов основано на :
- Состояние *Состояние контракта, указывающее на текущую конфигурацию контракта (права, остатки, переменные и т.д.);
- Логика бизнеса** (схема), определяющая, какие переходы разрешены и как они должны быть подтверждены;
- Контрактные операции**, которые шаг за шагом обновляют это состояние благодаря обязательствам, закрепленным в транзакциях Биткойна.
В следующей главе мы более подробно рассмотрим конкретное представление этих состояний и переходов состояний на внецепочечном уровне, а также то, как они связаны с UTXO и одноразовыми печатями, встроенными в Биткойн. Это даст возможность увидеть, как внутренняя механика RGB, основанная на валидации на стороне клиента, позволяет поддерживать согласованность смарт-контрактов, сохраняя конфиденциальность данных.
Контрактные операции RGB
В этой главе мы рассмотрим, как работают операции в смарт-контрактах и переходы состояний, опять же в рамках протокола RGB. Целью также будет понять, как несколько участников сотрудничают для передачи права собственности на актив.
Переходы состояний и их механика
Общий принцип все тот же - Client-side Validation, когда данные о состоянии хранятся у владельца и проверяются получателем. Однако специфика RGB заключается в том, что Боб, как получатель, просит Алису включить определенную информацию в данные контракта, чтобы иметь реальный контроль над полученным активом, через скрытую ссылку на один из своих UTXO.
Чтобы проиллюстрировать процесс перехода состояния (который является одной из фундаментальных контрактных операций в RGB), давайте рассмотрим пошаговый пример передачи активов между Алисой и Бобом:
*Начальная ситуация:
У Алисы есть тайник RGB с локально подтвержденными данными (клиент-сайд). Этот тайник относится к одному из ее UTXO на Bitcoin. Это означает, что определение печати в этих данных указывает на UTXO, принадлежащий Алисе. Идея заключается в том, чтобы дать ей возможность передать Бобу определенные цифровые права, связанные с активом (например, токены RGB).
У Боба тоже есть UTXO :
Боб, с другой стороны, имеет по крайней мере один собственный UTXO, без прямой связи с Алисой. В случае, если у Боба нет UTXO, все равно можно осуществить передачу ему с помощью самой свидетельской транзакции: выход этой транзакции будет включать обязательство (commitment) и неявно связывать право собственности на новый контракт с Бобом.
Строительство нового объекта недвижимости (Новое состояние) :
Боб посылает Алисе информацию, закодированную в виде инвойса (мы более подробно рассмотрим построение инвойсов в последующих главах), с просьбой создать новое состояние, соответствующее правилам контракта. Это состояние будет включать новое определение печати, указывающее на один из UTXO Боба. Таким образом, Боб получает право собственности на активы, определенные в этом новом состоянии, например, на определенное количество токенов RGB.
Подготовка образца сделки:
Затем Алиса создает транзакцию Bitcoin, расходуя UTXO, на который ссылалась
в предыдущей печати (та, которая легитимизировала ее как держателя). На
выходе этой транзакции вставляется обязательство (через Opret или Tapret) для закрепления нового состояния RGB. Обязательства Opret или Tapret берутся из MPC-дерева (как было показано в предыдущих
главах), которое может объединять несколько переходов из разных контрактов.
Передача Передачи Бобу:
Перед трансляцией транзакции Алиса отправляет Бобу Consignment, содержащее все необходимые данные клиентской стороны (его тайник) и информацию о новом состоянии в пользу Боба. В этот момент Боб применяет правила консенсуса RGB:
- Он проверяет все RGB-данные, содержащиеся в Consignment, включая новое состояние, которое дает ему право собственности на актив;
- Опираясь на Анкеты, включенные в Соглашение, он проверяет хронологию транзакций свидетелей (от Genesis до самого последнего перехода) и подтверждает соответствующие обязательства в блокчейне.
Завершение перехода:
Если Боба все устраивает, он может дать свое согласие (например, подписав соглашение). После этого Алиса может транслировать подготовленный образец транзакции. После подтверждения она закрывает печать, ранее принадлежавшую Алисе, и формализует право собственности Боба. Защита от двойной траты основана на том же механизме, что и в Биткойне: UTXO тратится, доказывая, что Алиса больше не может использовать его повторно.
Новое состояние теперь ссылается на UTXO Боба, передавая Бобу право собственности, которое ранее принадлежало Алисе. Вывод Bitcoin, в котором закреплены данные RGB, становится безотзывным доказательством передачи права собственности.
Пример минимального DAG (Directed Acyclic Graph), состоящего из двух контрактных операций (Genesis и State Transition), может проиллюстрировать, как состояние RGB (слой client-side, красный) соединяется с блокчейном Bitcoin (слой Commitment, оранжевый).
Он показывает, что Генезис определяет печать (определение печати), а затем переход состояния закрывает эту печать, чтобы создать новую в другом UTXO.
В связи с этим напомним несколько терминов:
- Задание*** сочетает в себе :
- Определение Уплотнение (которое указывает на UTXO);
- Владельческие состояния**, т.е. данные, связанные с владением (например, количество переданных токенов).
- Глобальное состояние** объединяет общие свойства контракта, видимые всем, и обеспечивает глобальную согласованность эволюций.
Переходы состояний**, описанные в предыдущей главе, являются основной формой работы с контрактами. Они ссылаются на одно или несколько предыдущих состояний (из Genesis или другого перехода состояния) и обновляют их до нового состояния.
На этой диаграмме показано, как в State Transition Bundle несколько
печатей могут быть закрыты в одной выборочной транзакции, одновременно
открывая новые печати. Действительно, интересной особенностью протокола RGB
является его способность к масштабированию: несколько переходов могут быть
объединены в пакет переходов, причем каждый пакет связан с отдельным листом
дерева MPC (уникальный идентификатор пакета). Благодаря механизму Deterministic Bitcoin Commitment (DBC), все сообщение вставляется в выход Tapret или Opret, при этом закрываются предыдущие печати и, возможно,
определяются новые. Якорь* служит прямой связью между обязательством,
хранящимся в блокчейне, и структурой проверки на стороне клиента (client-side).
В следующих главах мы рассмотрим все компоненты и процессы, связанные с созданием и проверкой перехода состояния. Большинство из этих элементов являются частью консенсуса RGB, реализованного в библиотеке RGB Core Library.
Переходный пакет
В RGB можно объединять различные переходы состояния, принадлежащие одному контракту (т. е. имеющие один и тот же ContractId, полученный из Genesis OpId). В простейшем случае, как между Алисой и Бобом в приведенном выше примере, Переходный пучок содержит только один переход. Однако поддержка операций с несколькими плательщиками (например, объединение монет, открытие канала Lightning и т. д.) означает, что несколько пользователей могут объединить свои переходы состояний в один пакет.
После сбора эти переходы закрепляются (с помощью механизма MPC + DBC) в одной транзакции Bitcoin:
- Каждый переход состояния хэшируется и группируется в пучок переходов;
- Пакет переходов хэшируется и вставляется в лист дерева MPC, соответствующий данному контракту (BundleId);
- Дерево MPC в конечном итоге задействуется через
OpretилиTapretв транзакции свидетеля, которая таким образом закрывает использованные печати и определяет новые.
Технически говоря, BundleId, вставляемый в лист MPC, получается из тегированного хэша, применяемого к строгой сериализации поля InputMap пакета:
BundleId = SHA256( SHA256(bundle_tag) || SHA256(bundle_tag) || InputMap )
В котором bundle_tag = urn:lnp-bp:rgb:bundle#2024-02-03,
например.
Карта InputMap - это структура данных, в которой для каждого входа i транзакции-образца указана ссылка на OpId соответствующего перехода
состояния. Например:
InputMap =
N input_0 OpId(input_0) input_1 OpId(input_1) ... input_N-1 OpId(input_N-1)
|____________________| |_________||______________| |_________||______________| |__________||_______________|
16-bit Little Endian 32-bit LE 32-byte hash
|_________________________| |_________________________| ... |___________________________|
MapElement1 MapElement2 MapElementN
N- это общее количество записей в транзакции, которые ссылаются наOpId;- opId(input_j)` - идентификатор операции одного из переходов состояния, присутствующих в связке.
Обращаясь к каждой записи только один раз и в упорядоченном порядке, мы предотвращаем двойное использование одной и той же печати при двух одновременных переходах из одного состояния в другое.
Генерация состояний и активное состояние
Переход состояния может использоваться для передачи права собственности на актив от одного лица к другому. Однако это не единственные возможные операции в протоколе RGB. В протоколе определены три контрактные операции:
- Переход состояния** ;
- Бытие** ;
- Расширение штата**.
Среди них Genesis и State Extension иногда называют "операциями генерации состояний", поскольку они создают новые состояния, не закрывая сразу ни одного. Это очень важный момент: Genesis и State Extension не предполагают закрытия печати. Скорее, они определяют новую печать, которая затем должна быть потрачена последующим Переходом состояния, чтобы быть действительно подтвержденной в истории блокчейна.
Активное состояние** контракта часто определяется как набор последних состояний, полученных в результате истории (DAG) транзакций, начиная с Genesis и следуя всем якорям в блокчейне Биткойна. Любые старые состояния, которые уже устарели (т. е. привязаны к отработанным UTXO), больше не считаются активными, но остаются важными для проверки согласованности истории.
Genesis
Генезис - это отправная точка каждого контракта RGB. Он создается эмитентом контракта и определяет начальные параметры в соответствии с Схемой. В случае с токеном RGB в Genesis может быть указано, например, :
- Количество первоначально созданных токенов и их владельцы;
- Общий возможный потолок эмиссии ;
- Любые правила перевыпуска, и какие участники имеют на это право.
Будучи первой транзакцией в контракте, Genesis не ссылается ни на какое предыдущее состояние и не закрывает никакую печать. Однако, чтобы появиться в истории и быть подтвержденным, Genesis должен быть потребован (закрыт) первым переходом состояния (часто это транзакция сканирования/авторасхода для самого эмитента или первоначальное распространение среди пользователей).
Расширение штата
Расширения состояний** предлагают оригинальную функцию для смарт-контрактов. Они позволяют выкупить определенные цифровые права (Валентности), предусмотренные в определении контракта, без немедленного закрытия печати. Чаще всего это касается :
- Проблемы с распределенными токенами;
- Механизмы обмена активами ;
- Условные перевыпуски (которые могут включать уничтожение других активов и т.д.).
Технически говоря, расширение состояния ссылается на Redeem (определенный тип RGB-входа), который соответствует Valency, определенной ранее (например, в Genesis или другом переходе состояния). Оно определяет новую печать, доступную тому человеку или состоянию, которое ею пользуется. Чтобы печать вступила в силу, она должна быть потрачена последующим Переходом состояния.
Например: Бытие создает право выдачи (Valency). Им может воспользоваться уполномоченный актор, который затем строит Расширение государства:
- Он относится к валентности (погашению);
- Он создает новое назначение (новые данные Состояния владельца), указывающее на UTXO;
- Будущий переход состояния, выпущенный владельцем этого нового UTXO, будет фактически передавать или распределять вновь выпущенные токены.
Компоненты контрактной операции
Теперь я хотел бы подробно рассмотреть каждый из составных элементов Операции по договору в RGB. Операция по договору - это действие, которое изменяет состояние договора и которое проверяется на стороне клиента, детерминированным образом, законным получателем. В частности, мы увидим, как операция по договору учитывает, с одной стороны, старое состояние (Old State) договора, а с другой - определение нового состояния (New State).
+---------------------------------------------------------------------------------------------------------------------+
| Contract Operation |
| |
| +-----+ +-----------------------+ +--------------------------------+ +---------+ +------------+ |
| | Ffv | | ContractId | SchemaId | | TransitionType | ExtensionType | | Testnet | | AltLayers1 | |
| +-----+ +-----------------------+ +--------------------------------+ +---------+ +------------+ |
| |
| +-----------------------------------------------+ +------------------------------------------------------------+ |
| | Metadata | | Global State | |
| | | | +----------------------------------+ | |
| | +-------------------------------------+ | | | +-------------------+ +--------+ | | |
| | | Structured Data | | | | | GlobalStateType | | Data | | ... ... | |
| | +-------------------------------------+ | | | +-------------------+ +--------+ | | |
| | | | +----------------------------------+ | |
| +-----------------------------------------------+ +------------------------------------------------------------+ | +------+
| +---------> OpId |
| +-----------------------------------------------+ +------------------------------------------------------------+ | +------+
| | Inputs | | Assignments | |
| | | | | |
| | +-------------------------------------------+ | | +--------------------------------------------------------+ | |
| | | Input #1 | | | | Assignment #1 | | |
+------+ | | | +----------+ +----------------+ +-------+ | | | | +----------------+ +-------------+ +-----------------+ | | | +--------------+
| OpId +--------------> PrevOpId | | AssignmentType | | Index | | | | | | AssignmentType | | Owned State | | Seal Definition +--------------> Bitcoin UTXO |
+------+ | | | +----------+ + ---------------+ +-------+ | | | | +----------------+ +-------------+ +-----------------+ | | | +--------------+
| | +-------------------------------------------+ | | +--------------------------------------------------------+ | |
| | | | | |
| | +-------------------------------------------+ | | +--------------------------------------------------------+ | |
| | | Input #2 | | | | Assignment #2 | | |
+------+ | | | +----------+ +----------------+ +-------+ | | | | +----------------+ +-------------+ +-----------------+ | | | +--------------+
| OpId +--------------> PrevOpId | | AssignmentType | | Index | | | | | | AssignmentType | | Owned State | | Seal Definition +--------------> Bitcoin UTXO |
+------+ | | | +----------+ +----------------+ +-------+ | | | | +----------------+ +-------------+ +-----------------+ | | | +--------------+
| | +-------------------------------------------+ | | +--------------------------------------------------------+ | |
| | | | | |
| | ... ... ... | | ... ... ... | |
| | | | | |
| +-----------------------------------------------+ +------------------------------------------------------------+ |
| |
| +-----------------------------------------------+ +------------------------------------------------------------+ |
| | Redeems | | Valencies | |
| | | | | |
| | +------------------------------+ | | | |
+------+ | | | +----------+ +-------------+ | | | +-------------+ +-------------+ | |
| OpId +--------------> PrevOpId | | ValencyType | | ... ... | | | ValencyType | | ValencyType | ... | |
+------+ | | | +----------+ +-------------+ | | | +-------------+ +-------------+ | |
| | +------------------------------+ | | | |
| | | | | |
| +-----------------------------------------------+ +------------------------------------------------------------+ |
| |
+---------------------------------------------------------------------------------------------------------------------+
Если мы посмотрим на диаграмму выше, то увидим, что операция Contract Operation включает элементы, относящиеся к Новому состоянию, и элементы, относящиеся к обновленному Старому состоянию.
Элементами Нового государства являются:
- Назначения**, в которых определены :
- Определение Уплотнение;
- Штат Область.
- Глобальное государство**, которое может быть изменено или обогащено;
- Валентности**, возможно, определенные в переходе состояния или генезисе.
Ссылка на Старое государство осуществляется через :
- Входы**, которые указывают на Присвоения предыдущих переходов состояний (отсутствуют в Genesis);
- Redeems**, которые ссылаются на ранее определенные валентности (только в State Extensions).
Кроме того, операция по контракту включает в себя более общие поля, характерные для данной операции:
- ffv` (Fast-forward version): 2-байтовое целое число, указывающее на версию контракта;
- transitionType
или ExtensionType: 16-битное целое число, определяющее тип перехода или расширения, в соответствии с бизнес-логикой; ContractId: 32-байтовое число, относящееся к OpId контракта Genesis. Включено в Transitions и Extensions, но не в Genesis;- schemaId: присутствует только в Genesis, это 32-байтовый хэш, представляющий структуру (Schema) контракта;
- testnet`: Булево значение, указывающее, находитесь ли вы в сети Testnet или Mainnet. Только для Genesis;
- altlayers1`: переменная, определяющая альтернативный слой (сайдчейн или другой), используемый для привязки данных в дополнение к Bitcoin. Присутствует только в Genesis ;
- metadata": поле, в котором может храниться временная информация, полезная для проверки сложного контракта, но которая не должна быть записана в историю финального статуса.
Наконец, все эти поля уплотняются с помощью специального процесса
хеширования, чтобы получить уникальный отпечаток пальца - OpId.
Этот OpId затем интегрируется в пакет перехода, позволяя ему проходить
аутентификацию и проверку в рамках протокола.
Поэтому каждая контрактная операция идентифицируется 32-байтным
хэшем с именем OpId. Этот хэш вычисляется путем
SHA256-хэширования всех элементов, составляющих операцию. Другими словами,
каждая контрактная операция имеет свое собственное криптографическое
обязательство, которое включает все данные, необходимые для проверки подлинности
и согласованности операции.
Контракт RGB идентифицируется по ContractId, полученному из
Genesis OpId (поскольку до Genesis не существует никакой
операции). Говоря конкретнее, мы берем Genesis OpId, меняем
порядок байт и применяем кодировку Base58. Такая кодировка делает ContractId более удобным для обработки и распознавания.
Методы и правила обновления статуса
Состояние контракта представляет собой набор информации, которую протокол RGB должен отслеживать для данного контракта. Он состоит из :
- Единое глобальное состояние**: это публичная, глобальная часть контракта, видимая всем;
- Одно или несколько государств-владельцев**: каждое государство-владелец
ассоциируется с уникальной печатью (и, следовательно, UTXO на Bitcoin).
Различают :
- Государства, находящиеся в государственной собственности,
- Государства, находящиеся в частной собственности.
Глобальное состояние* непосредственно включено в Операцию договора в виде отдельного блока. Состояния Собственности определяются в каждом Назначении, наряду с Определением уплотнения.
Важной особенностью RGB является способ изменения глобального состояния и состояния владения. В целом существует два типа поведения:
- Mutable**: когда элемент состояния описан как mutable, каждая новая операция заменяет предыдущее состояние новым. Старые данные при этом считаются устаревшими;
- Накопление**: когда элемент состояния определен как накапливающийся, каждая новая операция добавляет новую информацию к предыдущему состоянию, не перезаписывая его. В результате получается своего рода накопленная история.
Если в контракте элемент состояния не определен как мутабельный или кумулятивный, то для последующих операций этот элемент останется пустым (другими словами, для этого поля не будет новых версий). Именно схема контракта (т. е. закодированная бизнес-логика) определяет, является ли состояние (глобальное или собственное) мутабельным, кумулятивным или фиксированным. После определения Genesis эти свойства могут быть изменены только в том случае, если это разрешено самим контрактом, например, с помощью специального расширения State Extension.
В таблице ниже показано, как каждый тип операции контракта может манипулировать (или не манипулировать) глобальным состоянием и состоянием владельца:
| Генезис | Расширение состояния | Переход состояния | |
|---|---|---|---|
| Добавление Global State | + | - | + |
| Изменение Global State | n/a | - | + |
| Добавление Owned State | + | - | + |
| Изменение Owned State | n/a | Нет | + |
| Добавление Valencies | + | + | + |
+ : действие возможно, если схема контракта позволяет
это сделать.
-: операция должна быть подтверждена
последующим переходом состояния (само по себе продление состояния не
закрывает одноразовую пломбу).
Кроме того, временные рамки и права на обновление каждого типа данных можно различить в следующей таблице:
| Метаданные | Глобальное состояние | Владельческое состояние | |
|---|---|---|---|
| Область действия | Определено для одной операции контракта | Определено глобально для контракта | Определено для каждой печати (Assignment) |
| Кто может обновлять? | Не обновляется (эфемерные данные) | Операция, выполняемая участниками (эмитент и др.) | Зависит от законного владельца печати (того, кто может потратить её в следующей транзакции) |
| Временной охват | Только для текущей операции | Состояние устанавливается после операции | Состояние определяется до операции (Seal Definition из предыдущей операции) |
Глобальное государство
Глобальное государство часто описывают как "никто не владеет, все знают". Оно содержит общую информацию о контракте, которая является общедоступной. Например, в контракте на выпуск токенов оно потенциально содержит :
- Тикер (символическое сокращение токена):
ticker; - Полное имя токена:
name; - Точность (количество знаков после запятой):
precision; - Первоначальное предложение (и/или максимальный лимит токенов):
issuedSupply; - Дата выпуска:
создано; - Юридические данные или другая публичная информация:
data.
Это глобальное состояние может быть размещено на публичных ресурсах (веб-сайтах, IPFS, Nostr, Torrent и т. д.) и распространено среди сообщества. Кроме того, экономический стимул (необходимость хранить и передавать эти токены и т. д.) естественным образом побуждает контрактных пользователей самостоятельно поддерживать и распространять эти данные.
Задания
Задание Assignment - это базовая структура для определения :
- Печать (Seal Definition), которая указывает на конкретный UTXO;
- Состояние Состояние, т.е. свойство или данные, связанные с этой печатью.
Задание Assignment можно рассматривать как аналог вывода транзакции
Bitcoin, но с большей гибкостью. Здесь кроется логика передачи
собственности: Assignment связывает определенный тип актива или
права (AssignmentType) с печатью. Тот, кто владеет закрытым
ключом UTXO, связанным с этой печатью (или тот, кто может потратить этот
UTXO), считается владельцем этого Состояния.
Одна из сильных сторон RGB - возможность по своему усмотрению раскрывать (reveal) или скрывать (conceal) поля Seal Definition и Owned State. Это обеспечивает мощное сочетание конфиденциальности и
избирательности. Например, вы можете доказать, что переход действителен, не
раскрывая всех данных, предоставляя раскрытую версию тому, кто должен ее
подтвердить, а третьи лица видят только скрытую версию (хэш). На практике OpId перехода всегда вычисляется из скрытых данных.
Определение печати
В раскрытом виде Seal Definition имеет четыре основных поля: txptr, vout, blinding и method :
- txptr**: это ссылка на UTXO в Bitcoin:
- В случае с печатью Genesis она указывает непосредственно на существующий UTXO (тот, который связан с Genesis);
- В случае графовой печати мы можем иметь :
- Простой
txid, если указывает на конкретный UTXO, - Или
WitnessTx, который обозначает самоссылку: печать указывает на саму транзакцию. Это особенно полезно, когда внешний UTXO недоступен, например, в транзакциях открытия канала Lightning, или если у получателя нет UTXO.
- Простой
- vout** : номер выхода транзакции, указанной
txptr. Присутствует только для стандартной печати Graph (не дляWitnessTx); - blinding**: случайное число из 8 байт, для усиления конфиденциальности и предотвращения попыток грубой силы для идентификации UTXO;
- method** : указывает на используемый метод привязки (
TapretилиOpret).
Скрытая форма определения печати - это SHA256-хэш (метка) конкатенации этих 4 полей, с меткой, специфичной для RGB.
Владельческие штаты
Второй компонент Присвоения - это Собственное государство. В отличие от глобального государства, оно может существовать как в публичной, так и в частной форме:
- Государство, принадлежащее обществу**: все знают данные, связанные с печатью. Например, публичное изображение;
- Private Owned State**: данные скрыты, известны только владельцу (и, при необходимости, валидатору). Например, количество имеющихся токенов.
RGB определяет четыре возможных типа состояния (StateTypes) для состояния Owned:
- Декларативная**: не содержит числовых данных, только декларативное право (например, право голоса). Скрытая и открытая формы идентичны;
- Fungible**: представляет собой количество, которое можно менять (как
жетоны). В открытой форме у нас есть
суммаивязка. В скрытой форме у нас есть единственное обязательство Педерсена, которое скрывает количество и ослепление; - Структурированные**: хранит структурированные данные (до 64 кБ). В открытом виде это блоб данных. В скрытом виде это тегированный хэш этого блоба:
SHA-256(SHA-256(tag_data) || SHA-256(tag_data) || blob)
Например, с :
tag_data = urn:lnp-bp:rgb:state-data#2024-02-12
- Attachments**: связывает файл (аудио, изображение, бинарный файл и т.д.) с
владельцем, сохраняя хэш файла
file_hash, MIME-типmedia typeи криптографическую сольsalt. Сам файл размещается в другом месте. В скрытом виде он представляет собой хэш, помеченный тремя предыдущими элементами данных:
SHA-256(SHA-256(tag_attachment) || SHA-256(tag_attachment) || file_hash || media_type || salt)
Например, с :
tag_attachment = urn:rgb:state-attach#2024-02-12
Подводя итог, можно сказать, что здесь представлены 4 возможных типа состояния в открытом и скрытом виде:
State Concealed form Revealed form
+---------------------------------------------------------------------------------------------------------
+--------------------------------------------------------------------------------+
| |
Declarative | < void > |
| |
+--------------------------------------------------------------------------------+
+---------------------------------------------------------------------------------------------------------
+--------------------------+ +---------------------------------------+
| +----------------------+ | | +--------+ +----------+ |
Fungible | | Pedersen Commitement | | <========== | | Amount | | Blinding | |
| +----------------------+ | | +--------+ +----------+ |
+--------------------------+ +---------------------------------------+
+---------------------------------------------------------------------------------------------------------
+--------------------------+ +---------------------------------------+
| +----------------------+ | | +--------------------+ |
Structured | | Tagged Hash | | <========== | | Data Blob | |
| +----------------------+ | | +--------------------+ |
+--------------------------+ +---------------------------------------+
+---------------------------------------------------------------------------------------------------------
+--------------------------+ +---------------------------------------+
| +----------------------+ | | +-----------+ +------------+ +------+ |
Attachments | | Tagged Hash | | <========== | | File Hash | | Media Type | | Salt | |
| +----------------------+ | | +-----------+ +------------+ +------+ |
+--------------------------+ +---------------------------------------+
| Элемент | Декларативный | Фонгибельный | Структурированный | Вложения |
|---|---|---|---|---|
| Данные | Отсутствуют | Знаковое или беззнаковое 64-битное целое число | Любой строгий тип данных | Любой файл |
| Тип информации | Отсутствует | Знаковый или беззнаковый | Строгие типы | MIME-тип |
| Конфиденциальность | Не требуется | Pedersen commitment | Хеширование с ослеплением | Хешированный идентификатор файла |
| Ограничения по размеру | N/A | 256 байт | До 64 КБ | До ~500 ГБ |
Входы
Входы контрактной операции относятся к заданиям, которые расходуются в этой новой операции. Вход указывает на :
- prevOpId
: идентификатор (OpId`) предыдущей операции, в которой находилось Назначение; - assignmentType
: тип *назначения* (например,assetOwner` для токена) ; Index: индекс Назначения в списке, связанном с предыдущимOpId, определяемый после лексикографической сортировки скрытых печатей.
Входы никогда не появляются в Генезисе, так как не существует предыдущих Назначений. Они также не появляются в Расширениях штата (потому что Расширения штата не закрывают печати; скорее, они переопределяют новые печати на основе Значений).
Когда у нас есть Собственные состояния типа Fungible, логика
валидации (через скрипт AluVM, предоставленный в схеме) проверяет
согласованность сумм: сумма входящих токенов (Inputs) должна быть
равна сумме исходящих токенов (в новых Assignments).
Метаданные
Поле Метаданные может иметь размер до 64 килобайт и используется для включения временных данных, полезных для проверки, но не интегрированных в постоянное состояние контракта. Например, здесь могут храниться промежуточные переменные вычислений для сложных скриптов. Это пространство не предназначено для хранения в глобальной истории, поэтому оно находится вне сферы действия Owned States или Global State.
Валентности
Валентности** - это оригинальный механизм протокола RGB. Они могут быть
найдены в Генезисе, Переходах состояния или Расширениях состояния. Они
представляют собой числовые права, которые могут быть активированы
расширением состояния (через Redeems), а затем завершены
последующим переходом. Каждая валентность идентифицируется ValencyType (16 бит). Его семантика (право на перевыпуск, обмен
жетонов, право на сжигание и т.д.) определена в схеме.
Если говорить конкретнее, то мы можем представить себе генезис, определяющий валентность "право на перевыпуск". Расширение состояния будет потреблять его (Redeem) при выполнении определенных условий, чтобы ввести новое количество жетонов. Затем Переход состояния, исходящий от держателя созданной таким образом печати, может передать эти новые токены.
Искупает
Redeems - это эквивалент Valency для Inputs для Assignments. Они появляются только в Расширениях штата, поскольку именно там активируется ранее определенная валентность. Повторное использование состоит из двух полей:
PrevOpId:OpIdоперации, в которой было указано значение Valency;ValencyType: тип валентности, которую вы хотите активировать (каждыйValencyTypeможет быть использован только один раз в Расширении штата).
Например, Redeem может соответствовать выполнению CoinSwap, в зависимости от того, что было закодировано в Valency.
Характеристики состояния RGB
Сейчас мы рассмотрим несколько основных характеристик состояния в RGB. В частности, мы рассмотрим :
- Система Строгих типов, которая навязывает точную и типизированную организацию данных;
- Важность разделения утверждения и владения ;
- Система консенсусной эволюции в RGB, включающая понятия быстрое движение вперед и отталкивание назад.
Как всегда, помните, что все, что связано со статусом контракта, подтверждается на стороне клиента в соответствии с правилами консенсуса, изложенными в протоколе, конечная криптографическая ссылка которого закреплена в транзакциях Bitcoin.
Строгая система типов
RGB использует Строгую систему типов и детерминированный режим сериализации (Строгое кодирование). Такая организация призвана гарантировать идеальную воспроизводимость и точность в определении, обработке и проверке данных договора.
Во многих средах программирования (JSON, YAML...) структура данных может быть гибкой, даже слишком свободной. В RGB, с другой стороны, структура и типы каждого поля определены с явными ограничениями. Например
- Каждая переменная имеет определенный тип (например, 8-битное беззнаковое
целое
u8, или 16-битное знаковое целое и т.д.); - Типы могут быть составными (вложенные типы). Это означает, что вы можете
определить тип, основанный на других типах (например, агрегатный тип,
содержащий поле
u8, полеboolи т. д.); - Также можно задавать коллекции: списки (list), множества (set) или словари (map), с детерминированным порядком следования;
- Каждое поле ограничено (нижняя граница / верхняя граница). Мы также накладываем ограничения на количество элементов в коллекциях (containment);
- Данные выровнены по байтам, а сериализация строго определена и однозначна.
Благодаря этому строгому протоколу кодирования :
- Порядок расположения полей всегда одинаков, независимо от реализации или используемого языка программирования;
- Поэтому хэши, вычисленные на одном и том же наборе данных, воспроизводимы и идентичны (строго детерминированные обязательства);
- Границы предотвращают неконтролируемый рост объема данных (например, слишком большое количество полей);
- Такая форма кодирования облегчает криптографическую проверку, поскольку каждый участник точно знает, как сериализовать и хешировать данные.
На практике компилируется структура (Schema) и результирующий код (Interface и связанная с ним логика). Для определения контракта (типы, поля, правила) и создания строгого двоичного формата используется описательный язык. В результате компиляции получается :
- Макет памяти для каждого поля;
- Семантические идентификаторы (указывают, влияет ли изменение имени переменной на логику, даже если структура памяти остается прежней).
Строгая система типов также позволяет точно отслеживать изменения: любая модификация структуры (даже изменение имени поля) обнаруживается и может привести к изменению общего следа.
Наконец, при каждой компиляции создается "отпечаток пальца" - криптографический идентификатор, который подтверждает точную версию кода (данные, правила, проверка). Например, идентификатор вида :
BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana
Это позволяет управлять консенсусом или обновлениями реализации, обеспечивая при этом детальную отслеживаемость версий, используемых в сети.
Чтобы состояние контракта RGB не стало слишком громоздким для проверки на
стороне клиента, правило консенсуса устанавливает максимальный размер в 2^16 байт (64 Кио) для любых данных, участвующих в вычислениях для проверки. Это
относится к каждой переменной или структуре: не более 65536 байт или
эквивалент в числах (32768 16-битных целых чисел и т. д.). Это также
относится к коллекциям (спискам, наборам, картам), которые не могут
превышать 2^16 элементов.
Это ограничение гарантирует :
- Контролирует максимальный размер данных, которыми можно манипулировать во время перехода в состояние;
- Совместимость с виртуальной машиной (AluVM), используемой для запуска сценариев проверки.
Парадигма валидации != владения
Одно из главных новшеств RGB - строгое разделение двух понятий:
- Валидация**: проверка того, что переход состояния соответствует правилам контракта (бизнес-логика, история и т. д.);
- Владение** (владение, или контроль): факт владения биткойном UTXO, который позволяет потратить (или закрыть) одноразовую печать и, таким образом, осуществить переход состояния.
Валидация** происходит на уровне программного стека RGB (библиотеки, протокол обязательств и т.д.). Ее роль заключается в обеспечении соблюдения внутренних правил контракта (суммы, разрешения и т.д.). Наблюдатели или другие участники также могут проверять историю данных.
Владение**, с другой стороны, полностью полагается на безопасность Биткойна. Владение закрытым ключом UTXO означает контроль над возможностью запуска нового перехода (закрытие одноразовой печати). Таким образом, даже если кто-то может увидеть или подтвердить данные, он не сможет изменить состояние, если не владеет UTXO.
Такой подход ограничивает классические уязвимости, встречающиеся в более сложных блокчейнах (где весь код смарт-контракта является публичным и может быть изменен кем угодно, что иногда приводило к взломам). В RGB злоумышленник не может просто взаимодействовать с состоянием цепочки, поскольку право на действия с состоянием (владение) защищено слоем Биткойна.
Более того, такое разделение позволяет RGB естественным образом интегрироваться с Lightning Network. Каналы Lightning можно использовать для привлечения и перемещения активов RGB, не прибегая каждый раз к обязательствам на цепочке. Мы рассмотрим эту интеграцию RGB в Lightning более подробно в последующих главах курса.
Консенсусные разработки в RGB
Помимо семантического версионирования кода, RGB включает в себя систему развития или обновления правил консенсуса контракта с течением времени. Существует две основные формы эволюции:
- Перемотка вперед**
- Отталкивание** (на французском языке)
Ускоренный переход происходит, когда ранее недействительное правило
становится действительным. Например, если в контракте появляется новый тип AssignmentType или новое поле :
- Это нельзя сравнить с классическим хардфорком блокчейна, так как RGB работает в режиме проверки на стороне клиента и не влияет на общую совместимость блокчейна;
- На практике этот тип изменений обозначается полем
Ffv(быстрая передняя версия) в операции контракта; - Нынешние владельцы не пострадают: их статус останется в силе;
- Новые бенефициары (или новые пользователи), с другой стороны, должны обновить свое программное обеспечение (свой кошелек), чтобы узнать новые правила.
Откат означает, что ранее действовавшее правило становится недействительным. Таким образом, это "ужесточение" правил, но, строго говоря, не софтфорк:
- Существующие держатели могут пострадать (они могут обнаружить, что их активы устарели или стали недействительными в новой версии);
- Можно считать, что мы фактически создаем новый протокол: тот, кто принимает новое правило, отходит от старого;
- Эмитент может решить перевыпустить активы в новом протоколе, что вынудит пользователей вести два отдельных кошелька (один для старого протокола, другой для нового), если они хотят управлять обеими версиями.
В этой главе, посвященной контрактным операциям RGB, мы рассмотрели фундаментальные принципы, лежащие в основе этого протокола. Как вы заметили, сложность, присущая протоколу RGB, требует использования множества технических терминов. Поэтому в следующей главе я представлю вам глоссарий, который обобщит все понятия, рассмотренные в этой первой теоретической части, с определениями всех технических терминов, относящихся к RGB. Затем, в следующем разделе, мы рассмотрим определение и реализацию RGB-контрактов на практике.
Глоссарий RGB
Если вам понадобится вернуться к этому краткому глоссарию важных технических терминов, используемых в мире RGB (перечисленных в алфавитном порядке), он будет вам полезен. Эта глава не является необходимой, если вы уже поняли все, что мы рассмотрели в первом разделе.
AluVM
Аббревиатура AluVM расшифровывается как "Algorithmic logic unit Virtual Machine" - виртуальная машина на основе регистров, предназначенная для проверки смарт-контрактов и распределенных вычислений. Она используется (но не только) для проверки контрактов RGB. Таким образом, скрипты или операции, включенные в контракт RGB, могут быть выполнены в среде AluVM.
Дополнительная информация: Официальный сайт AluVM
Якорь
Якорь представляет собой набор данных на стороне клиента, используемых для доказательства включения уникальной коммисии в транзакцию. В протоколе RGB якорь состоит из следующих элементов:
- Идентификатор биткойн-транзакции (TXID) свидетеля транзакции;
- Мультипротокольное обязательство (MPC) ;
- Детерминированное обязательство Биткойна (DBC);
- Доказательство дополнительной транзакции (ETP), если используется механизм обязательств Tapret (см. раздел, посвященный этой модели).
Таким образом, якорь служит для установления проверяемой связи между конкретной транзакцией Bitcoin и приватными данными, подтвержденными протоколом RGB. Он гарантирует, что эти данные действительно включены в блокчейн, при этом их точное содержание не должно быть публично раскрыто.
Задание
В логике RGB назначение - это эквивалент транзакционного вывода, который изменяет, обновляет или создает определенные свойства в состоянии контракта. Назначение состоит из двух элементов:
- A Определение уплотнения (ссылка на конкретный UTXO) ;
- Состояние владельца (данные, описывающие состояние, связанное с этим новым владельцем).
Таким образом, присвоение указывает на то, что часть состояния (например, актив) теперь закреплена за конкретным держателем, идентифицированным с помощью одноразовой печати, связанной с UTXO.
Логика бизнеса
Бизнес-логика объединяет все правила и внутренние операции контракта, описанные его схемой (т. е. структурой самого контракта). Она определяет, как и при каких условиях может изменяться состояние контракта.
Удостоверение на стороне клиента
Под проверкой на стороне клиента понимается процесс, в ходе которого каждая сторона (клиент) проверяет набор данных, которыми обмениваются в частном порядке, в соответствии с правилами протокола. В случае RGB эти обменные данные группируются в так называемые согласования. В отличие от протокола Bitcoin, который требует публикации всех транзакций на цепочке, RGB позволяет публично хранить только обязательства (закрепленные в Bitcoin), в то время как основная информация о контракте (переходы, заверения, доказательства) остается вне цепочки и доступна только заинтересованным пользователям.
Обязательства
Обязательство (в криптографическом смысле) - это математический объект,
обозначаемый C, получаемый детерминированно из операции над
структурированными данными m (сообщение) и случайной величины r. Мы пишем :
C = \text{commit}(m, r) Этот механизм состоит из двух основных операций:
- Commit**: криптографическая функция применяется к сообщению
mи случайному числуrдля полученияC; - Verify**: мы используем
C, сообщениеmи значениеrдля проверки правильности данного обязательства. Функция возвращаетTrueилиFalse.
Обязательства должны соблюдать два свойства:
- Связка**: должно быть невозможно найти два разных сообщения, выдающих один
и тот же
C:
m' : \, | \, : m' \neq m \quad \text{and} \quad r' : \, | \, : r' \neq r \quad Такие как :
\text{verify}(m, r, C) = \text{verify}(m', r', C) \rightarrow \text{True} - Скрытие**: знание
Cне должно раскрывать содержимоеm.
В протоколе RGB обязательство включается в транзакцию Биткойна, чтобы доказать существование определенной части информации в определенный момент времени, не раскрывая саму информацию.
Консигнация
В консигнации группируются данные, которыми обмениваются стороны и которые подлежат валидации в RGB на стороне клиента. Существует две основные категории консигнации:
- Contract Consignment**: поставляется эмитентом (издателем контракта), включает в себя информацию об инициализации, такую как схема, генезис, интерфейс и реализация интерфейса.
- Transfer Consignment**: предоставляется плательщиком (payer). Содержит всю историю переходов состояний, ведущих к терминальному отправлению (т. е. конечному состоянию, полученному плательщиком).
Эти партии не записываются публично в блокчейн; они обмениваются напрямую между заинтересованными сторонами по выбранному ими каналу связи.
Контракт
Контракт - это набор прав, оформленных в цифровом виде между несколькими участниками по протоколу RGB. Он имеет активное состояние и бизнес-логику, определяемую схемой, которая указывает, какие операции разрешены (передачи, продления и т. д.). Состояние контракта, а также правила его действия выражаются в схеме. В любой момент времени контракт изменяется только в соответствии с тем, что разрешено этой схемой и скриптами валидации (запускаемыми, например, в AluVM).
Работа по контракту
Операция по договору - это обновление статуса договора, выполняемое в соответствии с правилами схемы. В RGB существуют следующие операции:
- Переход состояния** ;
- Бытие** ;
- Расширение штата**.
Каждая операция изменяет состояние, добавляя или заменяя определенные данные (глобальное состояние, состояние владельца...).
Участник контракта
Участник контракта - это субъект, который принимает участие в операциях, связанных с контрактом. В RGB проводится различие между :
- Эмитент контракта, который создает Генезис (происхождение контракта);
- Стороны контракта, т.е. обладатели прав на состояние контракта;
- Государственные стороны, которые могут строить государственные расширения, если контракт предлагает доступные для общественности валентности.
Права по договору
Права по контракту - это различные права, которые могут быть реализованы участниками контракта RGB. Они делятся на несколько категорий:
- Права собственности**, связанные с владением конкретным UTXO (через Определение печати);
- Исполнительные права**, т.е. возможность построить один или несколько переходов (State Transitions) в соответствии со схемой;
- Публичные права**, когда схема разрешает определенное публичное использование, например, создание расширения штата через выкуп валентности.
Состояние контракта
Состояние контракта соответствует текущему состоянию контракта в определенный момент времени. Он может состоять как из публичных, так и из приватных данных, отражающих состояние контракта. RGB различает :
- Глобальное состояние, которое включает в себя публичные свойства контракта (установленные в Genesis или добавленные через авторизованные обновления);
- Владельческие государства**, которые принадлежат конкретным владельцам, идентифицируемым по их UTXO.
Детерминированное обязательство биткойна - DBC
Детерминированная фиксация Биткойна (DBC) - это набор правил, используемых для доказательной и однозначной регистрации коммитмента в транзакции Биткойна. В протоколе RGB существует две основные формы DBC:
- Opret**
- Тапрет**
Эти механизмы определяют, как именно обязательство кодируется в выходных данных или структуре транзакции Биткойна, чтобы гарантировать, что это обязательство детерминированно отслеживается и проверяется.
Направленный ациклический граф - DAG
DAG (или Acyclic Guided Graph) - это граф без циклов, позволяющий осуществлять топологическое планирование. Блокчейны, как и шарды контрактов RGB, могут быть представлены в виде DAG.
Дополнительная информация: Directed Acyclic Graph
Гравировка
Гравировка - это необязательная строка данных, которую сменяющие друг друга владельцы контракта могут внести в историю контракта. Эта функция существует, например, в интерфейсе RGB21 и позволяет добавлять в историю контрактов памятную или описательную информацию.
Дополнительное доказательство транзакции - ETP
ETP (Extra Transaction Proof) - это часть Anchor, содержащая дополнительные данные, необходимые для подтверждения Tapret commitment (в контексте taproot). Она включает в себя, помимо прочего, внутренний открытый ключ скрипта taproot (internal PubKey) и информацию, специфичную для Script Path Spend.
Genesis
Genesis - это набор данных, регулируемых схемой, который формирует начальное состояние любого контракта в RGB. Его можно сравнить с концепцией Genesis Block в Биткойне или с концепцией транзакций Coinbase, но здесь на уровне клиента и токенов RGB.
Глобальное государство
Глобальное состояние - это набор публичных свойств, содержащихся в состоянии контракта. Оно определяется в Genesis и, в зависимости от правил контракта, может быть обновлено авторизованными переходами. В отличие от собственных состояний, глобальное состояние не принадлежит конкретному субъекту; оно ближе к публичному реестру внутри контракта.
Интерфейс
Интерфейс - это набор инструкций, используемых для декодирования двоичных данных, собранных в схеме или в операциях контракта и их состояниях, чтобы сделать их читаемыми для пользователя или его кошелька. Он действует как интерпретационный слой.
Реализация интерфейса
Реализация интерфейса - это набор деклараций, которые связывают интерфейс со схемой. Она обеспечивает семантический перевод, выполняемый самим интерфейсом, так что исходные данные контракта могут быть понятны пользователю или соответствующему программному обеспечению (кошелькам).
Счет-фактура
Счет-фактура имеет вид URL-адреса, закодированного в base58, который содержит данные, необходимые для построения перехода состояния (плательщиком). Другими словами, это счет, позволяющий контрагенту (плательщику) создать соответствующий переход для передачи актива или обновления состояния контракта.
Сеть молний
Lightning Network - это децентрализованная сеть платежных каналов (или государственных каналов) Биткойна, состоящая из 2/2 кошельков с несколькими подписями. Она обеспечивает быстрые и недорогие нецепочечные транзакции, опираясь при этом на первый уровень Биткойна для арбитража (или закрытия), когда это необходимо.
Для получения более подробной информации о том, как работает Lightning, я рекомендую вам пройти этот другой курс:
https://planb.network/courses/34bd43ef-6683-4a5c-b239-7cb1e40a4aeb
Многопротокольное обязательство - MPC
Мультипротокольное обязательство (MPC) относится к структуре дерева Меркла, используемой в RGB для включения в одну транзакцию Биткойна нескольких Переходных пакетов из разных контрактов. Идея заключается в том, чтобы сгруппировать несколько обязательств (потенциально соответствующих разным контрактам или разным активам) в одной точке привязки, чтобы оптимизировать занятие пространства блока.
Владение государством
Владельческое состояние - это часть контрактного состояния, которая заключена в Назначении и связана с конкретным владельцем (через одноразовую печать, указывающую на UTXO). Она представляет собой, например, цифровой актив или конкретное контрактное право, закрепленное за данным лицом.
Собственность
Владение означает возможность контролировать и расходовать UTXO, на который ссылается определение печати. Когда государство-владелец связано с UTXO, владелец этого UTXO имеет право, потенциально, передавать или эволюционировать связанное государство, в соответствии с правилами контракта.
Частично подписанная транзакция биткойна - PSBT
PSBT (Partially Signed Bitcoin Transaction) - это транзакция Bitcoin, которая еще не полностью подписана. Она может быть разделена между несколькими организациями, каждая из которых может добавлять или проверять определенные элементы (подписи, скрипты...), пока транзакция не будет признана готовой для распространения на цепи.
Дополнительная информация: BIP-0174
Обязательства Педерсена
Обязательство Педерсена - это тип криптографического обязательства, обладающий свойством быть гомоморфным по отношению к операции сложения. Это означает, что можно подтвердить сумму двух обязательств, не раскрывая их отдельных значений.
Формально, если :
C1=\text{commit}(m1,r1) \quad C2=\text{commit}(m2,r2) затем
C3=C1⋅C2=\text{commit}(m1+m2, r1+r2) Это свойство полезно, например, для сокрытия количества обмениваемых токенов, но при этом для проверки итогов.
Дополнительная информация: Pedersen commitment
Выкупить
В расширении штата под Redeem понимается действие по возвращению (или использованию) ранее объявленной Valency. Поскольку валентность - это публичное право, выкуп позволяет уполномоченному участнику претендовать на конкретное расширение штата контракта.
Схема
Схема в RGB - это декларативный фрагмент кода, описывающий набор переменных, правил и бизнес-логики (Business Logic), которые управляют работой контракта. Схема определяет структуру состояний, типы допустимых переходов и условия проверки.
Определение печати
Определение печати - это часть Назначения, которая связывает обязательство с UTXO, принадлежащим новому владельцу. Другими словами, она указывает, где находится условие (в каком UTXO), и устанавливает право собственности на актив или право.
Осколок
Осколок представляет собой ветвь в DAG истории переходов состояний контракта RGB. Другими словами, это связное подмножество общей истории контракта, соответствующее, например, последовательности переходов, необходимых для доказательства действительности данного актива с момента генезиса.
Одноразовое уплотнение
Одноразовая печать - это криптографическое обещание принять на себя обязательства в отношении пока неизвестного сообщения, которое будет раскрыто только один раз в будущем и должно быть известно всем членам определенной аудитории. Цель состоит в том, чтобы предотвратить создание нескольких конкурирующих обязательств для одной и той же печати.
Тайник
Тайник - это набор данных на стороне клиента, которые пользователь хранит для одного или нескольких контрактов RGB с целью проверки (Client-side Validation). Сюда входит история переходов, отправлений, подтверждений действительности и т. д. Каждый держатель сохраняет только те части истории, которые ему нужны (shards).
Расширение штата
Продление состояния - это операция контракта, используемая для повторного запуска обновления состояния путем погашения ранее объявленных Валентностей. Чтобы быть эффективным, продление состояния должно быть закрыто переходом состояния (который обновляет конечное состояние контракта).
Переход состояния
Переход состояния - это операция, которая изменяет состояние RGB-контракта на новое. Она может изменять данные глобального состояния и/или состояния владельца. На практике каждый переход проверяется правилами схемы и закрепляется в блокчейне Биткойна с помощью коммитмента.
Taproot
Относится к формату транзакций биткойна Segwit v1, представленному в BIP341 и BIP342. Taproot улучшает конфиденциальность и гибкость криптовалют, в частности, делая транзакции более компактными и трудноотличимыми друг от друга.
Конечная отправка - конечный пункт отправки
Конечная отправка (или Конечная точка отправки) - это передаточная отправка, содержащая окончательное состояние контракта, включая переход состояния, созданный на основе счета-фактуры получателя (плательщика). Таким образом, это конечная точка передачи, содержащая необходимые данные для подтверждения передачи права собственности или состояния.
Переходный пакет
Пакет переходов - это набор переходов состояния RGB (принадлежащих одному контракту), которые участвуют в одной и той же свидетельской транзакции Bitcoin. Это позволяет объединить несколько обновлений или переходов в один якорь на цепи.
UTXO
Биткойн UTXO (Unspent Transaction Output) определяется хэшем транзакции и выходным индексом (vout). Иногда его также называют outpoint. В протоколе RGB ссылка на UTXO (через Seal Definition) позволяет определить местонахождение Owned State, то есть имущества, хранящегося в блокчейне.
Валентность
Валентность - это публичное право, которое не требует хранения государства как такового, но которое может быть выкуплено через Продление государства. Таким образом, это форма открытой для всех (или определенных игроков) возможности, заявленной в логике контракта, для осуществления определенного расширения в более поздний срок.
Сделка со свидетелем
Транзакция свидетеля - это транзакция Биткойна, которая закрывает одноразовую печать вокруг сообщения, содержащего многопротокольное обязательство (MPC). Эта транзакция тратит UTXO или создает его, чтобы запечатать обязательство, связанное с протоколом RGB. Она действует как внутрицепочечное доказательство того, что состояние было установлено в определенный момент времени.
Программирование на RGB
Реализация контрактов RGB
В этой главе мы подробно рассмотрим, как определяется и реализуется контракт RGB. Мы увидим, из каких компонентов состоит RGB-контракт, каковы их роли и как они строятся.
Компоненты договора RGB
До сих пор мы уже обсуждали Генезис, который представляет собой отправную точку контракта, и видели, как он сочетается с логикой Операции контракта и состоянием протокола. Однако полное определение контракта RGB не ограничивается только Генезисом: оно включает три дополнительных компонента, которые вместе составляют сердце реализации.
Первый компонент называется Схема. Это файл, описывающий фундаментальную структуру и бизнес-логику (бизнес-логику) контракта. В нем указываются используемые типы данных, правила проверки, разрешенные операции (например, первоначальный выпуск токена, передача, особые условия и т. д.) - словом, общие рамки, определяющие, как работает контракт.
Второй компонент - это интерфейс. Он фокусируется на том, как пользователи (и, соответственно, программное обеспечение портфеля) будут взаимодействовать с этим контрактом. Он описывает семантику, то есть читаемое представление различных полей и действий. Таким образом, в то время как схема определяет, как контракт работает технически, интерфейс определяет, как представить и показать эти функциональные возможности: имена методов, отображение данных и т. д.
Третий компонент - Реализация интерфейса, который дополняет два предыдущих, выступая в роли своеобразного моста между схемой и интерфейсом. Другими словами, она связывает семантику, выраженную интерфейсом, с базовыми правилами, определенными в схеме. Именно эта реализация будет управлять, например, преобразованием между параметром, введенным в кошелек, и двоичной структурой, налагаемой протоколом, или компиляцией правил валидации на машинном языке.
Эта модульность - интересная особенность RGB, поскольку она позволяет разным группам разработчиков работать отдельно над этими аспектами (схема, интерфейс, реализация), при условии, что они следуют правилам консенсуса протокола.
В общем, каждый контракт состоит из :
- Genesis**, который является начальным состоянием контракта (и может быть уподоблен специальной транзакции, определяющей первое владение активом, правом или любыми другими параметризуемыми данными);
- Схема**, которая описывает бизнес-логику контракта (типы данных, правила проверки и т.д.);
- Интерфейс**, который обеспечивает семантический слой как для кошельков, так и для пользователей, проясняя процесс чтения и выполнения транзакций;
- Интерфейс Implementation**, который устраняет разрыв между бизнес-логикой и представлением, чтобы гарантировать, что определение контракта соответствует пользовательскому опыту.
Важно отметить, что для того, чтобы кошелек мог управлять RGB-активом (будь то сменный токен или право любого вида), в нем должны быть собраны все эти элементы: Схема, Интерфейс, Реализация интерфейса и Генезис. Все это передается через контрактное соглашение, т. е. пакет данных, содержащий все необходимое для подтверждения контракта на стороне клиента.
Чтобы прояснить эти понятия, приведем сводную таблицу, в которой компоненты контракта RGB сравниваются с концепциями, уже известными в объектно-ориентированном программировании (ООП) или в экосистеме Ethereum:
| Компонент контракта RGB | Значение | Эквивалент OOP | Эквивалент Ethereum |
|---|---|---|---|
| Genesis | Начальное состояние контракта | Конструктор класса | Конструктор контракта |
| Schema | Бизнес-логика контракта | Класс | Контракт |
| Interface | Семантика контракта | Интерфейс (Java) / Трейт (Rust) / Протокол (Swift) | Стандарт ERC |
| Interface Implementation | Сопоставление семантики и логики | Impl (Rust) / Implements (Java) | Application Binary Interface (ABI) |
В левой колонке показаны элементы, характерные для протокола RGB. В среднем столбце указана конкретная функция каждого компонента. Затем, в колонке "OOP-эквивалент", мы находим эквивалентный термин в объектно-ориентированном программировании:
- Genesis играет роль, аналогичную роли конструктора класса: именно здесь инициализируется состояние контракта;
- Схема** - это описание класса, т.е. определение его свойств, методов и логики, лежащей в основе;
- Интерфейс ** соответствует интерфейсам (Java), трайтам (Rust) или протоколам (Swift): это публичные определения функций, событий, полей... ;
- Реализация Интерфейса соответствует Impl в Rust или Implements в Java, где мы указываем, как код будет выполнять методы, объявленные в интерфейсе.
В контексте Ethereum Genesis ближе к конструктору контракта, Schema - к определению контракта, Interface - к стандарту, такому как ERC-20 или ERC-721, а Interface Implementation - к ABI (Application Binary Interface), который определяет формат взаимодействия с контрактом.
Преимущество модульности RGB также заключается в том, что различные заинтересованные стороны могут написать, например, собственную реализацию интерфейса, при условии, что они соблюдают логику Схемы и семантику Интерфейса. Таким образом, эмитент может разработать новый, более удобный фронт-энд (интерфейс), не изменяя логику контракта, или, наоборот, можно расширить схему для добавления функциональности и предоставить новую версию адаптированной реализации интерфейса, в то время как старые реализации останутся действительными для базовой функциональности.
Когда мы составляем новый контракт, мы генерируем Genesis (первый шаг к выпуску или распространению актива), а также его компоненты (схему, интерфейс, реализацию интерфейса). После этого контракт полностью готов к работе и может быть распространен среди кошельков и пользователей. Этот метод, при котором Genesis сочетается с этими тремя компонентами, гарантирует высокую степень кастомизации (каждый контракт может иметь свою собственную логику), децентрализации (каждый может внести свой вклад в тот или иной компонент) и безопасности (проверка остается строго определенной протоколом, не завися от произвольного кода на цепи, как это часто бывает в других блокчейнах).
Теперь я хотел бы подробнее рассмотреть каждый из этих компонентов: схему, интерфейс и реализацию интерфейса.
Схема
В предыдущем разделе мы увидели, что в экосистеме RGB контракт состоит из нескольких элементов: Генезиса, который устанавливает начальное состояние, и нескольких других дополнительных компонентов. Назначение схемы - декларативно описать всю бизнес-логику контракта, то есть структуру данных, используемые типы, разрешенные операции и их условия. Поэтому она является очень важным элементом для обеспечения работоспособности контракта на стороне клиента, поскольку каждый участник (например, кошелек) должен проверять, что получаемые им переходы состояния соответствуют логике, определенной в схеме.
Схему можно сравнить с "классом" в объектно-ориентированном программировании (ООП). В общем случае она служит моделью, определяющей компоненты контракта, такие как :
- Различные типы состояний и присвоений ;
- Валентности, т.е. специальные права, которые могут быть задействованы (выкуплены) при выполнении определенных операций;
- Поля Global State, которые описывают глобальные, публичные и общие свойства контракта;
- Структура Genesis (самая первая операция, активирующая контракт) ;
- Разрешенные формы переходов и расширений состояний, а также то, как эти операции могут изменить ;
- Метаданные, связанные с каждой операцией, для хранения временной или дополнительной информации;
- Правила, определяющие, как могут изменяться данные внутреннего контракта (например, является ли поле мутабельным или кумулятивным);
- Последовательности операций, которые считаются допустимыми: например, порядок переходов, который должен быть соблюден, или набор логических условий, которые должны быть выполнены.
Когда эмитент актива на RGB публикует контракт, он предоставляет Genesis и схему, связанную с ним. Пользователи или кошельки, желающие взаимодействовать с активом, получают эту схему, чтобы понять логику контракта и впоследствии убедиться в легитимности переходов, в которых они будут участвовать.
Первым шагом для всех, кто получает информацию об активе RGB (например, о передаче токена), является проверка этой информации на соответствие схеме. Для этого необходимо использовать компиляцию схемы для :
- Проверьте, что собственные состояния, назначения и другие элементы определены правильно и что они соблюдают наложенные типы (так называемая строгая система типов);
- Проверьте выполнение правил перехода (скрипты валидации). Эти сценарии могут быть запущены через AluVM, который присутствует на стороне клиента и отвечает за проверку согласованности бизнес-логики (сумма перевода, специальные условия и т. д.).
На практике Schema не является исполняемым кодом, что можно наблюдать в блокчейнах, хранящих код на цепочке (EVM в Ethereum). Напротив, RGB отделяет бизнес-логику (декларативную) от исполняемого кода на блокчейне (который ограничен криптографическими якорями). Таким образом, схема определяет правила, но применение этих правил происходит вне блокчейна, на сайте каждого участника, в соответствии с принципом Client-side Validation.
Схема должна быть скомпилирована, прежде чем ее можно будет использовать в
RGB-приложениях. В результате компиляции создается двоичный файл (например, .rgb) или зашифрованный двоичный файл (.rgba). Когда кошелек
импортирует этот файл, он знает, что :
- Как выглядит каждый тип данных (целые числа, структуры, массивы...) благодаря строгой системе типов;
- Как должен быть структурирован Genesis (для понимания инициализации активов);
- Различные типы операций (переходы состояния, расширения состояния) и то, как они могут изменять состояние;
- Правила сценариев (введенные в схему), которые движок AluVM будет применять для проверки валидности операций.
Как объяснялось в предыдущих главах, строгая система типов дает нам стабильный, детерминированный формат кодирования: все переменные, будь то собственные состояния, глобальные состояния или значения, описываются точно (размер, нижние и верхние границы, если необходимо, знаковый или беззнаковый тип и т. д.). Также можно определять вложенные структуры, например, для поддержки сложных сценариев использования.
Опционально схема может ссылаться на корневой SchemaId, что
облегчает повторное использование существующей базовой структуры (шаблона).
Таким образом, вы можете развивать контракт или создавать вариации
(например, новый тип токена) на основе уже проверенного шаблона. Такая
модульность позволяет избежать необходимости создавать целые контракты
заново и способствует стандартизации лучших практик.
Еще один важный момент заключается в том, что логика эволюции состояния (передачи, обновления и т. д.) описывается в схеме в виде скриптов, правил и условий. Так, если разработчик контракта хочет разрешить перевыпуск или навязать механизм сжигания (уничтожение токенов), он может указать соответствующие скрипты для AluVM в валидационной части схемы.
Отличие от программируемых цепных блокчейнов
В отличие от таких систем, как Ethereum, где код смарт-контракта (исполняемый файл) записан в самом блокчейне, RGB хранит контракт (его логику) вне цепочки, в виде скомпилированного декларативного документа. Это означает, что :
- В каждом узле сети Биткойн не существует полной по Тьюрингу виртуальной машины. Правила контракта RGB выполняются не в блокчейне, а у каждого пользователя, который хочет подтвердить состояние;
- Данные о контрактах не загрязняют блокчейн: только криптографические
доказательства (обязательства) включаются в транзакции Bitcoin
(через
TapretилиOpret); - Схема может быть обновлена или отклонена (fast-forward, push-back и т. д.), не требуя форка блокчейна Биткойна. Кошельки просто должны импортировать новую схему и адаптироваться к изменениям консенсуса.
Использование эмитентом и пользователями
Когда эмитент создает актив (например, неинфляционный взаимозаменяемый токен), он подготавливает :
- Схема, описывающая правила эмиссии, передачи и т.д. ;
- Генезис, адаптированный к данной схеме (с общим количеством выпущенных токенов, идентификацией первоначального владельца, любыми специальными ценностями для повторного выпуска и т.д.).
Затем он делает скомпилированную схему (файл .rgb) доступной
для пользователей, чтобы любой, кто получает передачу этого токена, мог
проверить согласованность операции на месте. Без этой схемы пользователь не
смог бы интерпретировать данные о статусе или проверить их соответствие
правилам контракта.
Таким образом, когда новый кошелек хочет поддерживать какой-либо актив, ему нужно просто интегрировать соответствующую схему. Этот механизм позволяет добавлять совместимость с новыми типами RGB-активов, не меняя программную основу кошелька: все, что требуется, - это импортировать бинарную схему и понять ее структуру.
Схема определяет бизнес-логику в RGB. В ней перечислены правила эволюции контракта, структура его данных (Owned States, Global State, Valencies) и связанные с ними скрипты проверки (исполняемые AluVM). Благодаря этому декларативному документу определение контракта (скомпилированный файл) четко отделено от фактического выполнения правил (на стороне клиента). Такое разделение придает RGB большую гибкость, позволяя использовать широкий спектр сценариев (сменные токены, NFT, более сложные контракты), избегая при этом сложности и недостатков, характерных для программируемых блокчейнов на цепочке.
Пример схемы
Давайте рассмотрим конкретный пример схемы для контракта RGB. Это выдержка
на языке Rust из файла nia.rs (инициалы для "Неинфляционные активы"), который определяет модель для сменных токенов, которые не могут быть
перевыпущены сверх их первоначального запаса (неинфляционный актив). Этот
тип токенов можно рассматривать как эквивалент ERC20 во вселенной RGB в
Ethereum, т. е. взаимозаменяемые токены, которые соблюдают определенные
базовые правила (например, в отношении трансферов, инициализации запасов и
т. д.).
Прежде чем погрузиться в код, стоит напомнить общую структуру RGB-схемы. В ней есть ряд деклараций, обрамляющих :
- Возможный
SchemaId, указывающий на использование другой базовой схемы в качестве шаблона; - Государства Глобальные государства и Собственные государства (с их строгими типами) ;
- Валентности** (если есть);
- Операции (Генезис, Переходы состояний, Расширения состояний), которые могут ссылаться на эти состояния и валентности;
- Система строгих типов, используемая для описания и проверки данных;
- Скрипты проверки** (запускаются через AluVM).
В приведенном ниже коде показано полное определение схемы Rust Schema. Мы будем комментировать его по частям, следуя аннотациям (1) - (9) ниже:
// ===== PART 1: Function Header and SubSchema =====
fn nia_schema() -> SubSchema {
// definitions of libraries and variables
// ===== PART 2: General Properties (ffv, subset_of, type_system) =====
Schema {
ffv: zero!(),
subset_of: None,
type_system: types.type_system(),
// ===== PART 3: Global States =====
global_types: tiny_bmap! {
GS_NOMINAL => GlobalStateSchema::once(types.get("RGBContract.DivisibleAssetSpec")),
GS_DATA => GlobalStateSchema::once(types.get("RGBContract.ContractData")),
GS_TIMESTAMP => GlobalStateSchema::once(types.get("RGBContract.Timestamp")),
GS_ISSUED_SUPPLY => GlobalStateSchema::once(types.get("RGBContract.Amount")),
},
// ===== PART 4: Owned Types =====
owned_types: tiny_bmap! {
OS_ASSET => StateSchema::Fungible(FungibleType::Unsigned64Bit),
},
// ===== PART 5: Valencies =====
valency_types: none!(),
// ===== PART 6: Genesis: Initial Operations =====
genesis: GenesisSchema {
metadata: Ty::<SemId>::UNIT.id(None),
globals: tiny_bmap! {
GS_NOMINAL => Occurrences::Once,
GS_DATA => Occurrences::Once,
GS_TIMESTAMP => Occurrences::Once,
GS_ISSUED_SUPPLY => Occurrences::Once,
},
assignments: tiny_bmap! {
OS_ASSET => Occurrences::OnceOrMore,
},
valencies: none!(),
},
// ===== PART 7: Extensions =====
extensions: none!(),
// ===== PART 8: Transitions: TS_TRANSFER =====
transitions: tiny_bmap! {
TS_TRANSFER => TransitionSchema {
metadata: Ty::<SemId>::UNIT.id(None),
globals: none!(),
inputs: tiny_bmap! {
OS_ASSET => Occurrences::OnceOrMore,
},
assignments: tiny_bmap! {
OS_ASSET => Occurrences::OnceOrMore,
},
valencies: none!(),
}
},
// ===== PART 9: Script AluVM and Entry Points =====
script: Script::AluVM(AluScript {
libs: confined_bmap! { alu_id => alu_lib },
entry_points: confined_bmap! {
EntryPoint::ValidateGenesis => LibSite::with(FN_GENESIS_OFFSET, alu_id),
EntryPoint::ValidateTransition(TS_TRANSFER) => LibSite::with(FN_TRANSFER_OFFSET, alu_id),
},
}),
}
}
- (1) - Заголовок функции и подсхема**
Функция nia_schema() возвращает SubSchema,
указывая на то, что данная схема может частично наследоваться от более общей
схемы. В экосистеме RGB такая гибкость позволяет повторно использовать
некоторые стандартные элементы основной схемы, а затем определять правила,
специфичные для конкретного контракта. В данном случае мы решили не включать
наследование, так как subset_of будет равно None.
- (2) - Общие свойства: ffv, subset_of, type_system**
Свойство ffv соответствует быстрой версии контракта.
Значение zero!() здесь указывает на то, что мы находимся в версии
0 или начальной версии этой схемы. Если впоследствии вы захотите добавить новые
функциональные возможности (новый тип операции и т.д.), вы можете увеличить значение
этой версии, чтобы указать на изменение консенсуса.
Свойство subset_of: None подтверждает отсутствие наследования.
Поле type_system ссылается на строгую систему типов, уже
определенную в библиотеке types. Эта строка указывает на то,
что все данные, используемые контрактом, используют строгую реализацию
сериализации, предоставляемую данной библиотекой.
- (3) - Глобальные государства
В блоке global_types мы объявляем четыре элемента. Мы
используем ключ, такой как GS_NOMINAL или GS_ISSUED_SUPPLY, чтобы ссылаться на них в дальнейшем:
GS_NOMINALссылается на типDivisibleAssetSpec, который описывает различные поля создаваемого токена (полное имя, тикер, точность...);GS_DATAпредставляет общие данные, такие как отказ от ответственности, метаданные или другой текст;GS_TIMESTAMPуказывает на дату выпуска;GS_ISSUED_SUPPLYустанавливает общее предложение, то есть максимальное количество токенов, которое может быть создано.
Ключевое слово once(...) означает, что каждое из этих полей может
появиться только один раз.
- (4) - Владельческие типы
В owned_types мы объявляем OS_ASSET, который
описывает состояние fungible. Мы используем StateSchema::Fungible(FungibleType::Unsigned64Bit), указывая,
что количество активов (токенов) хранится в виде 64-битного беззнакового
целого. Таким образом, любая транзакция будет отправлять определенное
количество единиц этого токена, которое будет проверяться в соответствии с
этой строго типизированной числовой структурой.
- (5) - Валентности**
Мы указываем valency_types: none!(), что означает, что в этой
схеме нет валентностей, другими словами, нет специальных или дополнительных
прав (таких как перевыпуск, условный ожог и т.д.). Если бы схема включала
их, они были бы объявлены в этом разделе.
- (6) - Бытие: первые операции
Здесь мы вступаем в ту часть, которая объявляет об операциях по контракту. Бытие описывается :
- Отсутствие
метаданных(полеметаданные: Ty::<SemId>::UNIT.id(None)) ; - Глобальные состояния, которые должны присутствовать по одному разу (
Once); - Список Назначений, в котором
OS_ASSETдолжен появлятьсяОдин раз или больше. Это означает, что Genesis требуется хотя бы одно назначениеOS_ASSET(начальный держатель); - Нет валентности :
valencies: none!().
Таким образом, мы ограничиваем определение начальной эмиссии токенов: мы
должны объявить выпущенную поставку (GS_ISSUED_SUPPLY), а также
как минимум одного держателя (Owned State типа OS_ASSET).
- (7) - Расширения
Поле extensions: none!() указывает на то, что в данном контракте
не предусмотрено расширение состояния. Это означает, что не существует операции
выкупа цифрового права (Valency) или расширения состояния перед Переходом. Все
делается через Genesis или Переходы состояния.
- (8) - Переходы: TS_TRANSFER
В переходах мы определяем тип операции TS_TRANSFER. Мы объясняем, что :
- У него нет метаданных;
- Он не изменяет глобальное состояние (которое уже определено в Genesis);
- В качестве входных данных он принимает один или несколько
OS_ASSET. Это означает, что он должен расходовать существующие собственные состояния; - Он создает (
назначает) по крайней мере один новыйOS_ASSET(другими словами, получатель или получатели получают токены); - Он не генерирует новые валентности.
Это моделирует поведение базового трансфера, который расходует токены на UTXO, затем создает новые Owned States в пользу получателей, и таким образом сохраняет равенство общей суммы между входами и выходами.
- (9) - Скрипт AluVM и точки входа** (на французском языке)
Наконец, мы объявляем скрипт AluVM (Script::AluVM(AluScript { ... })). Этот скрипт содержит :
- Одна или несколько внешних библиотек (
libs), которые будут использоваться при проверке; - Точки входа, указывающие на смещения функций в коде AluVM, соответствующие
валидации Genesis (
ValidateGenesis) и каждого объявленного перехода (ValidateTransition(TS_TRANSFER)).
Этот код проверки отвечает за применение бизнес-логики. Например, он будет проверять :
- Что
GS_ISSUED_SUPPLYне превышен во время Genesis ; - Чтобы сумма
входов(потраченных жетонов) равнялась сумменазначений(полученных жетонов) дляTS_TRANSFER.
Если эти правила не соблюдаются, переход будет считаться недействительным.
Этот пример схемы "Не надуваемый надувной актив" дает нам лучшее понимание структуры простого контракта с надувными токенами RGB. Мы можем четко видеть разделение между описанием данных (Глобальные и Владельческие состояния), объявлением операций (Генезис, Переходы, Расширения) и реализацией проверки (AluVM-скрипты). Благодаря этой модели токен ведет себя как классический сменный токен, но при этом остается валидированным на стороне клиента и не зависит от внутрицепочечной инфраструктуры для выполнения своего кода. В блокчейне Биткойна закреплены только криптографические обязательства.
Интерфейс
Интерфейс - это слой, предназначенный для того, чтобы сделать контракт читаемым и манипулируемым как для пользователей (чтение человеком), так и для портфелей (чтение программным обеспечением). Таким образом, интерфейс играет роль, сравнимую с ролью интерфейса в объектно-ориентированном языке программирования (Java, Rust trait и т. д.), поскольку он раскрывает и уточняет функциональную структуру контракта, не обязательно раскрывая внутренние детали бизнес-логики.
В отличие от схемы, которая является чисто декларативной и компилируется в двоичный файл, который трудно использовать как есть, интерфейс предоставляет ключи для чтения, необходимые для :
- Перечислите и опишите глобальные государства и государства-владельцы, включенные в контракт;
- Получите доступ к названиям и значениям каждого поля, чтобы их можно было отобразить (например, для токена узнать его тикер, максимальную сумму и т. д.);
- Интерпретируйте и стройте операции контракта (генезис, переход в состояние или расширение состояния), связывая данные с понятными именами (например, выполните перевод, четко указав "сумму", а не двоичный идентификатор).
Благодаря интерфейсу вы можете, например, написать код в кошельке, который вместо манипуляций с полями будет напрямую манипулировать метками, такими как "количество токенов", "название актива" и т. д. Таким образом, управление контрактом становится более интуитивным. Таким образом, управление контрактами становится более интуитивным.
Общая эксплуатация
Этот метод имеет множество преимуществ:
- Стандартизация:**
Один и тот же тип контракта может поддерживаться стандартным интерфейсом, общим для нескольких реализаций кошелька. Это облегчает совместимость и повторное использование кода.
- Четкое разделение между схемой и интерфейсом:**
В дизайне RGB схема (бизнес-логика) и интерфейс (представление и манипулирование) - это две независимые сущности. Разработчики, которые пишут контрактную логику, могут сосредоточиться на схеме, не заботясь об эргономике или представлении данных, в то время как другая команда (или та же самая команда, но в другие сроки) может разрабатывать интерфейс.
- Гибкая эволюция:**
Интерфейс может быть изменен или дополнен после выпуска актива, без необходимости изменять сам контракт. Это существенное отличие от некоторых систем смарт-контрактов на цепочке, где интерфейс (часто смешанный с кодом исполнения) заморожен в блокчейне.
- Возможность работы с несколькими интерфейсами
Один и тот же контракт может быть представлен через различные интерфейсы, адаптированные к различным потребностям: простой интерфейс для конечного пользователя, другой, более продвинутый, для эмитента, которому необходимо управлять сложными операциями конфигурации. Кошелек может выбирать, какой интерфейс импортировать, в зависимости от его использования.
На практике, когда кошелек получает RGB-контракт (через файл .rgb или .rgba), он также импортирует связанный с ним интерфейс,
который также компилируется. Во время выполнения кошелек может, например, :
- Просмотрите список государств и прочитайте их названия, чтобы отобразить на пользовательском интерфейсе тикер, начальную сумму, дату выпуска и т.д., а не нечитаемый цифровой идентификатор;
- Постройте операцию (например, перевод), используя явные имена параметров:
вместо того чтобы написать
assignments { OS_ASSET => 1 }, можно предложить пользователю поле "Сумма" в форме и преобразовать эту информацию в строго типизированные поля, ожидаемые контрактом.
Отличие от Ethereum и других систем
В Ethereum интерфейс (описанный через ABI, Application Binary Interface) обычно формируется из хранимого на цепочке кода (смарт-контракта). Изменение конкретной части интерфейса, не затрагивая сам контракт, может быть дорогостоящим или сложным. Однако RGB основан на полностью внецепочечной логике, а данные хранятся в обязательствах на Биткойне. Такая конструкция позволяет изменять интерфейс (или его реализацию), не влияя на фундаментальную безопасность контракта, поскольку проверка бизнес-правил остается в схеме и коде AluVM.
Компиляция интерфейса
Как и в случае со схемой, интерфейс определяется в исходном коде (часто на
языке Rust) и компилируется в файл .rgb или .rgba.
Этот двоичный файл содержит всю информацию, необходимую кошельку для :
- Идентифицируйте поля по имени ;
- Привяжите каждое поле (и его значение) к строгому системному типу, определенному в контракте;
- Знайте, какие операции разрешены и как их выполнять.
После импорта интерфейса кошелек может корректно отображать контракт и предлагать пользователю взаимодействие.
Интерфейсы, стандартизированные ассоциацией LNP/BP
В экосистеме RGB интерфейс используется для придания читабельного и манипулируемого смысла данным и операциям контракта. Таким образом, интерфейс дополняет схему, которая описывает внутреннюю бизнес-логику (строгие типы, скрипты валидации и т. д.). В этом разделе мы рассмотрим стандартные интерфейсы, разработанные ассоциацией LNP/BP для распространенных типов контрактов (сменные токены, NFT и т. д.).
Напомним, что идея заключается в том, что каждый интерфейс описывает, как
отображать и манипулировать контрактом на стороне кошелька, четко называя
поля (такие как spec, ticker, issuedSupply...) и определяя возможные операции (такие как Transfer, Burn, Rename...). Несколько
интерфейсов уже работают, но в будущем их будет становиться все больше и
больше.
Некоторые готовые к использованию интерфейсы
RGB20 - это интерфейс для взаимозаменяемых активов, который можно сравнить со стандартом ERC20 в Ethereum. Однако он идет на шаг дальше, предлагая более широкую функциональность:
- Например, возможность переименовать актив (изменить тикер или полное название) после его выпуска или скорректировать его точность (сплиты акций);
- В нем также могут быть описаны механизмы вторичного перевыпуска (ограниченного или неограниченного) и сжигания с последующей заменой, чтобы уполномочить эмитента уничтожать, а затем воссоздавать активы при определенных условиях;
Например, интерфейс RGB20 может быть связан со схемой Non-Inflatable Asset (NIA), которая устанавливает ненадуваемый первоначальный объем поставки, или с другими более продвинутыми схемами, если это необходимо.
RGB21 относится к контрактам типа NFT или, в более широком смысле, к любому уникальному цифровому контенту, такому как представление цифровых медиа (изображения, музыка и т.д.). Помимо описания выпуска и передачи одного актива, он включает в себя такие функции, как :
- Встроенная поддержка прямого включения файла (до 16 МБ) в контракт (для получения на стороне клиента);
- Возможность для владельца внести "гравировку" в историю, чтобы доказать прошлое владение NFT.
RGB25 - это гибридный стандарт, сочетающий в себе сменные и несменные аспекты. Он предназначен для частично взаимозаменяемых активов, таких как токенизация недвижимости, когда вы хотите разделить объект недвижимости, сохранив при этом связь с единым корневым активом (другими словами, у вас есть взаимозаменяемые части дома, связанные с неперемещаемым домом). Технически этот интерфейс можно связать со схемой *Collectible Fungible Asset (CFA)**, которая учитывает понятие разделения при отслеживании исходного актива.
Разрабатываемые интерфейсы
Другие интерфейсы планируются для более специализированного использования, но пока не доступны:
- RGB22**, посвященный цифровым идентификаторам, для управления идентификаторами и профилями на цепочке в экосистеме RGB;
- RGB23**, для расширенной маркировки времени, использующей некоторые идеи Opentimestamps, но с функциями отслеживания;
- RGB24**, целью которой является создание эквивалента децентрализованной системы доменных имен (DNS), подобной Ethereum Name Service ;
- RGB26**, предназначенная для управления DAO (децентрализованная автономная организация) в более сложном формате (управление, голосование и т.д.);
- RGB30**, очень похожий на RGB20, но с учетом децентрализованной первичной эмиссии и использования государственных расширений. Он будет использоваться для активов, перевыпуском которых управляют несколько организаций, или при соблюдении более тонких условий.
Конечно, в зависимости от даты, на которую вы изучаете этот курс, эти интерфейсы могут уже работать и быть доступными.
Пример интерфейса
В этом фрагменте кода Rust показан интерфейс RGB20 (функциональный актив). Этот код взят из файла rgb20.rs в стандартной
библиотеке RGB. Давайте посмотрим на него, чтобы понять структуру интерфейса
и то, как он обеспечивает мост между, с одной стороны, бизнес-логикой (определенной
в схеме) и, с другой стороны, функциональными возможностями, открытыми для кошельков
и пользователей.
// ...
fn rgb20() -> Iface {
let types = StandardTypes::with(rgb20_stl());
Iface {
version: VerNo::V1,
name: tn!("RGB20"),
global_state: tiny_bmap! {
fname!("spec") => GlobalIface::required(types.get("RGBContract.DivisibleAssetSpec")),
fname!("data") => GlobalIface::required(types.get("RGBContract.ContractData")),
fname!("created") => GlobalIface::required(types.get("RGBContract.Timestamp")),
fname!("issuedSupply") => GlobalIface::one_or_many(types.get("RGBContract.Amount")),
fname!("burnedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")),
fname!("replacedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")),
},
assignments: tiny_bmap! {
fname!("inflationAllowance") => AssignIface::public(OwnedIface::Amount, Req::NoneOrMore),
fname!("updateRight") => AssignIface::public(OwnedIface::Rights, Req::Optional),
fname!("burnEpoch") => AssignIface::public(OwnedIface::Rights, Req::Optional),
fname!("burnRight") => AssignIface::public(OwnedIface::Rights, Req::NoneOrMore),
fname!("assetOwner") => AssignIface::private(OwnedIface::Amount, Req::NoneOrMore),
},
valencies: none!(),
genesis: GenesisIface {
metadata: Some(types.get("RGBContract.IssueMeta")),
global: tiny_bmap! {
fname!("spec") => ArgSpec::required(),
fname!("data") => ArgSpec::required(),
fname!("created") => ArgSpec::required(),
fname!("issuedSupply") => ArgSpec::required(),
},
assignments: tiny_bmap! {
fname!("assetOwner") => ArgSpec::many(),
fname!("inflationAllowance") => ArgSpec::many(),
fname!("updateRight") => ArgSpec::optional(),
fname!("burnEpoch") => ArgSpec::optional(),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_RESERVES
},
},
transitions: tiny_bmap! {
tn!("Transfer") => TransitionIface {
optional: false,
metadata: None,
globals: none!(),
inputs: tiny_bmap! {
fname!("previous") => ArgSpec::from_non_empty("assetOwner"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_non_empty("assetOwner"),
},
valencies: none!(),
errors: tiny_bset! {
NON_EQUAL_AMOUNTS
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("Issue") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.IssueMeta")),
globals: tiny_bmap! {
fname!("issuedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_non_empty("inflationAllowance"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_many("assetOwner"),
fname!("future") => ArgSpec::from_many("inflationAllowance"),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
ISSUE_EXCEEDS_ALLOWANCE,
INSUFFICIENT_RESERVES
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("OpenEpoch") => TransitionIface {
optional: true,
metadata: None,
globals: none!(),
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnEpoch"),
},
assignments: tiny_bmap! {
fname!("next") => ArgSpec::from_optional("burnEpoch"),
fname!("burnRight") => ArgSpec::required()
},
valencies: none!(),
errors: none!(),
default_assignment: Some(fname!("burnRight")),
},
tn!("Burn") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.BurnMeta")),
globals: tiny_bmap! {
fname!("burnedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnRight"),
},
assignments: tiny_bmap! {
fname!("future") => ArgSpec::from_optional("burnRight"),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_COVERAGE
},
default_assignment: None,
},
tn!("Replace") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.BurnMeta")),
globals: tiny_bmap! {
fname!("replacedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnRight"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_many("assetOwner"),
fname!("future") => ArgSpec::from_optional("burnRight"),
},
valencies: none!(),
errors: tiny_bset! {
NON_EQUAL_AMOUNTS,
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_COVERAGE
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("Rename") => TransitionIface {
optional: true,
metadata: None,
globals: tiny_bmap! {
fname!("new") => ArgSpec::from_required("spec"),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("updateRight"),
},
assignments: tiny_bmap! {
fname!("future") => ArgSpec::from_optional("updateRight"),
},
valencies: none!(),
errors: none!(),
default_assignment: Some(fname!("future")),
},
},
extensions: none!(),
error_type: types.get("RGB20.Error"),
default_operation: Some(tn!("Transfer")),
type_system: types.type_system(),
}
}
В этом интерфейсе мы замечаем сходство со структурой схемы: мы находим объявление глобального состояния, принадлежащих состояний, операций контракта (генезис и переходы), а также обработку ошибок. Однако интерфейс фокусируется на представлении и манипулировании этими элементами для кошелька или любого другого приложения.
Разница со Schema заключается в природе типов. В Schema используются строгие
типы (например, FungibleType::Unsigned64Bit) и более
технические идентификаторы. В интерфейсе используются имена полей, макросы (fname!(), tn!()) и ссылки на классы аргументов (ArgSpec, OwnedIface::Rights...). Цель здесь - облегчить функциональное
понимание и организацию элементов для кошелька.
Кроме того, интерфейс может вводить дополнительную функциональность в
базовую схему (например, управление правом burnEpoch), если это
остается согласованным с окончательной проверенной логикой на стороне
клиента. Раздел "скрипт" AluVM в схеме будет обеспечивать криптографическую
валидность, в то время как интерфейс описывает, как пользователь (или
кошелек) взаимодействует с этими состояниями и переходами.
Глобальное состояние и задания
В разделе global_state находятся такие поля, как spec (описание актива), data, created, issuedSupply, burnedSupply, replacedSupply. Это поля, которые кошелек может прочитать и
представить. Например:
specотобразит конфигурацию токена;issuedSupplyилиburnedSupplyдают нам общее количество выпущенных или сожженных токенов и т.д.
В разделе Назначения мы определяем различные роли или права. Например:
Владелец активасоответствует владению токенами (это взаимозаменяемое Владельческое состояние);burnRightсоответствует способности сжигать жетоны;- updateRight` соответствует праву на переименование актива.
Ключевое слово public или private (например, AssignIface::public(...)) указывает, являются ли эти состояния
видимыми (public) или конфиденциальными (private).
Что касается Req::NoneOrMore, Req::Optional, то
они указывают на ожидаемое возникновение.
Генезис и переходы
Часть genesis описывает, как инициализируется актив:
- Поля
spec,data,created,issuedSupplyявляются обязательными (ArgSpec::required()); - Назначения, такие как
assetOwner, могут присутствовать в нескольких экземплярах (ArgSpec::many()), что позволяет распределять токены между несколькими первоначальными держателями; - Такие поля, как
inflationAllowanceилиburnEpoch, могут быть (или не быть) включены в Genesis.
Затем для каждого перехода (Transfer, Issue, Burn...) интерфейс определяет, какие поля операция ожидает
получить на вход, какие поля операция выдаст на выход и какие ошибки могут
возникнуть. Например:
Переход :
- Входы:
предыдущий→ должен бытьвладельцем актива; - Назначения:
бенефициар→ будет новымвладельцем активов; - Ошибка:
NON_EQUAL_AMOUNTS(таким образом, кошелек сможет обрабатывать случаи, когда входная сумма не соответствует выходной).
Переход Выпуск :
- Необязательно (
optional: true), так как дополнительное излучение не обязательно активируется; - Входы:
used→inflationAllowance, т.е. разрешение на добавление новых токенов; - Назначения:
бенефициар(полученные новые жетоны) ибудущее(оставшийсяинфляционный запас); - Возможные ошибки:
SUPPLY_MISMATCH,ISSUE_EXCEEDS_ALLOWANCEи т. д.
Переход ожога :
- Входы :
использованный→ aburnRight; - Globals :
burnedSupplyтребуется ; - Назначения:
future→ возможное продолжениеburnRight, если мы еще не все сожгли; - Ошибки:
UPPLY_MISMATCH,INVALID_PROOF,INSUFFICIENT_COVERAGE.
Поэтому каждая операция описывается так, чтобы ее мог прочитать кошелек. Это
позволяет отобразить графический интерфейс, в котором пользователь может
ясно увидеть: "У вас есть право на сжигание. Хотите ли вы сжечь определенную
сумму? Код знает, что нужно заполнить поле burnedSupply и
проверить, что burnRight является действительным.
Подводя итог, важно помнить, что интерфейс, каким бы полным он ни был, сам по себе не определяет внутреннюю логику контракта. Основную работу выполняет Схема, которая включает в себя строгие типы, структуру Genesis, переходы и так далее. Интерфейс просто раскрывает эти элементы в более интуитивном и именованном виде для использования в приложении.
Благодаря модульности RGB, интерфейс можно модернизировать (например,
добавить переход Rename, исправить отображение поля и т. д.)
без необходимости переписывать весь контракт. Пользователи этого интерфейса
могут немедленно воспользоваться этими улучшениями, как только они обновят
файл .rgb или .rgba.
Но как только вы объявили интерфейс, вам нужно связать его с соответствующей
схемой. Это делается с помощью Interface Implementation, которая определяет, как сопоставить каждое именованное поле (например, fname!("assetOwner")) со строгим идентификатором (например, OS_ASSET), определенным в схеме. Это гарантирует, например, что
когда кошелек манипулирует полем burnRight, это состояние,
которое в схеме описывает возможность сжигать токены.
Реализация интерфейса
В архитектуре RGB мы видели, что каждый компонент (схема, интерфейс и т. д.) может быть разработан и скомпилирован независимо. Однако есть один незаменимый элемент, который связывает эти различные строительные блоки воедино: Реализация интерфейса. Это то, что явно сопоставляет идентификаторы или поля, определенные в схеме (со стороны бизнес-логики), с именами, объявленными в интерфейсе (со стороны представления и взаимодействия с пользователем). Таким образом, когда кошелек загружает контракт, он может точно понять, какое поле чему соответствует, и как операция, названная в интерфейсе, связана с логикой схемы.
Важным моментом является то, что реализация интерфейса не обязательно должна раскрывать все функциональные возможности схемы или все поля интерфейса: она может быть ограничена некоторым подмножеством. На практике это позволяет ограничить или отфильтровать определенные аспекты схемы. Например, вы можете иметь схему с четырьмя типами операций, но интерфейс реализации, который отображает только два из них в данном контексте. И наоборот, если интерфейс предлагает дополнительные конечные точки, мы можем не реализовывать их здесь.
Вот классический пример реализации интерфейса, в котором мы связываем схему Non-Inflatable Asset (NIA) с интерфейсом RGB20:
fn nia_rgb20() -> IfaceImpl {
let schema = nia_schema();
let iface = Rgb20::iface();
IfaceImpl {
version: VerNo::V1,
schema_id: schema.schema_id(),
iface_id: iface.iface_id(),
script: none!(),
global_state: tiny_bset! {
NamedField::with(GS_NOMINAL, fname!("spec")),
NamedField::with(GS_DATA, fname!("data")),
NamedField::with(GS_TIMESTAMP, fname!("created")),
NamedField::with(GS_ISSUED_SUPPLY, fname!("issuedSupply")),
},
assignments: tiny_bset! {
NamedField::with(OS_ASSET, fname!("assetOwner")),
},
valencies: none!(),
transitions: tiny_bset! {
NamedType::with(TS_TRANSFER, tn!("Transfer")),
},
extensions: none!(),
}
}
В этом интерфейсе реализации :
- Мы явно ссылаемся на схему через
nia_schema()и на интерфейс черезRgb20::iface(). Вызовыchema.schema_id()иiface.iface_id()используются для привязки реализации интерфейса на стороне компиляции (это связывает криптографические идентификаторы этих двух компонентов); - Между элементами схемы и элементами интерфейса устанавливается
соответствие. Например, поле
GS_NOMINALв схеме связано со строкой"spec"на стороне интерфейса (NamedField::with(GS_NOMINAL, fname!("spec"))). То же самое мы делаем для операций, таких какTS_TRANSFER, которую мы связываем с"Transfer"в интерфейсе... ; - Мы видим, что здесь нет валентностей (
valencies: none!()) или расширений (extensions: none!()), что отражает тот факт, что этот контракт NIA не использует эти возможности.
В результате компиляции получается отдельный файл .rgb или .rgba, который импортируется в кошелек в дополнение к Схеме и
Интерфейсу. Таким образом, программное обеспечение знает, как конкретно
соединить этот контракт NIA (логика которого описывается его схемой) с
интерфейсом "RGB20" (который предоставляет человеческие имена и режим
взаимодействия для сменных токенов), применяя эту реализацию интерфейса в
качестве шлюза между ними.
Зачем нужна отдельная реализация интерфейса?
Разделение повышает гибкость. Одна схема может иметь несколько различных реализаций интерфейса, каждая из которых отображает свой набор функциональных возможностей. Более того, сама реализация интерфейса может развиваться или переписываться, не требуя изменений ни в схеме, ни в интерфейсе. Это сохраняет принцип модульности RGB: каждый компонент (схема, интерфейс, реализация интерфейса) может быть изменен и обновлен независимо, при условии соблюдения правил совместимости, налагаемых протоколом (одинаковые идентификаторы, согласованность типов и т. д.).
В конкретном случае, когда кошелек загружает контракт, он должен :
- Загрузите скомпилированную Схему (чтобы узнать структуру бизнес-логики);
- Загрузите скомпилированный интерфейс (для понимания имен и операций на стороне пользователя) ;
- Загрузите скомпилированную Реализацию интерфейса (чтобы связать логику схемы с именами интерфейсов, операция за операцией, поле за полем).
Эта модульная архитектура делает возможными такие сценарии использования, как :
- Ограничьте определенные операции для определенных пользователей: предложите частичный интерфейс реализации, который дает доступ только к базовым переводам, не предлагая, например, функции сжигания или обновления;
- Представление изменений: разработать реализацию интерфейса, которая переименовывает поле в интерфейсе или отображает его по-другому, не изменяя основу контракта;
- Поддержка нескольких схем: кошелек может загружать несколько реализаций интерфейса для одного и того же типа интерфейса, чтобы работать с разными схемами (разными логиками токенов), при условии, что их структура совместима.
В следующей главе мы рассмотрим, как работает передача контракта и как формируются счета-фактуры RGB.
Переводы по контрактам
В этой главе мы проанализируем процесс передачи контракта в экосистеме RGB.
Для иллюстрации мы рассмотрим Алису и Боба, наших обычных героев, которые
хотят обменяться активами RGB. Мы также покажем некоторые фрагменты команд
из командной строки инструмента rgb, чтобы увидеть, как он
работает на практике.
Понимание передачи договора RGB
Давайте рассмотрим пример перевода между Алисой и Бобом. В этом примере мы предполагаем, что Боб только начинает использовать RGB, а Алиса уже имеет активы RGB в своем кошельке. Мы увидим, как Боб настраивает свою среду, импортирует соответствующий контракт, затем запрашивает перевод у Алисы и, наконец, как Алиса осуществляет фактическую транзакцию на блокчейне Биткойна.
1) Установка кошелька RGB
Прежде всего Бобу нужно установить RGB-кошелек, то есть программное обеспечение, совместимое с протоколом. Изначально он не содержит никаких контрактов. Бобу также понадобится :
- Биткойн-кошелек для управления вашими UTXO;
- Соединение с узлом Bitcoin (или с сервером Electrum), чтобы вы могли идентифицировать свои UTXO и распространять транзакции в сети.
Напомним, что Обладающие состояния в RGB относятся к
биткоин UTXO. Поэтому мы всегда должны быть в состоянии управлять и тратить
UTXO в транзакции Bitcoin, которая включает криптографические обязательства
(Tapret или Opret), указывающие на данные RGB.
2) Получение информации о контракте
Затем Бобу нужно получить интересующие его данные о контракте. Эти данные могут распространяться по любому каналу: веб-сайт, электронная почта, приложение для обмена сообщениями... На практике они группируются в соглашение, то есть небольшой пакет данных, содержащий :
- Генезис, который определяет начальное состояние контракта;
- Схема**, которая описывает бизнес-логику (строгие типы, скрипты проверки и т. д.);
- Интерфейс**, определяющий уровень представления (имена полей, доступные операции);
- Реализация интерфейса, которая конкретно связывает схему с интерфейсом.
Общий размер часто составляет порядка нескольких килобайт, поскольку каждый компонент обычно весит менее 200 байт. Можно также транслировать эту партию в Base58, по каналам, устойчивым к цензуре (например, через Ностр или Lightning Network), или в виде QR-кода.
3) Импорт и проверка контрактов
Получив груз, Боб импортирует его в свой кошелек RGB. После этого :
- Убедитесь, что Genesis и Schema действительны;
- Интерфейс загрузки и реализация интерфейса ;
- Обновляйте данные, хранящиеся на стороне клиента.
Теперь Боб может видеть актив в своем кошельке (даже если он им еще не владеет) и понимать, какие поля доступны, какие операции возможны... Затем ему нужно связаться с человеком, который на самом деле владеет активом, подлежащим передаче. В нашем примере это Алиса.
Процесс обнаружения владельца определенного актива RGB аналогичен поиску плательщика биткойнов. Детали этого соединения зависят от способа использования (маркетплейсы, приватные каналы чата, выставление счетов, продажа товаров и услуг, заработная плата...).
4) Выставление счета-фактуры
Чтобы начать передачу актива RGB, Боб должен сначала выставить счет-фактуру. Этот счет-фактура используется для :
- Сообщите Алисе тип операции, которую необходимо выполнить (например,
Передачаиз интерфейса RGB20); - Предоставьте Алисе определение печати Боба (т.е. UTXO, где он хочет получить актив);
- Укажите необходимое количество активного ингредиента (например, 100 единиц).
Боб использует инструмент rgb в командной строке. Предположим,
ему нужно 100 единиц токена, чей ContractId известен, он хочет
полагаться на Tapret и указывает его UTXO (456e3..dfe1:0):
bob$ rgb invoice RGB20 100 <ContractId> tapret1st:456e3..dfe1:0
В конце этой главы мы подробнее рассмотрим структуру RGB-счетов.
5) Передача счетов-фактур
Сформированный счет-фактура (например, в виде URL: rgb:2WBcas9.../RGB20/100+utxob:...) содержит всю информацию, необходимую Алисе для подготовки перевода. Как и
накладная, она может быть закодирована в компактном виде (Base58 или другой
формат) и отправлена через приложение для обмена сообщениями, электронную
почту, Nostr...
6) Подготовка транзакций на стороне Алисы
Алиса получает счет от Боба. В ее RGB-кошельке есть тайник, содержащий актив, который нужно перевести. Чтобы потратить UTXO, содержащий актив, она должна сначала сгенерировать PSBT (Partially Signed Bitcoin Transaction), то есть неполную транзакцию Bitcoin, используя имеющийся у нее UTXO:
alice$ wallet construct tx.psbt
Эта базовая транзакция (пока без подписи) будет использована для закрепления
криптографического обязательства, связанного с передачей Бобу. Таким
образом, UTXO Алисы будет потрачен, а на выходе мы разместим обязательство Tapret или Opret для Боба.
7) Формирование передаточной партии
Затем Алиса создает терминальную партию (иногда называемую "передаточной партией") с помощью команды :
alice$ rgb transfer tx.psbt <invoice> consignment.rgb
Этот новый файл consignment.rgb содержит :
- Полная история переходов государств, необходимых для подтверждения актива, вплоть до настоящего времени (с момента Генезиса);
- Новый переход состояния, который передает активы от Алисы к Бобу в соответствии с выставленным Бобом счетом;
- Незавершенная транзакция Bitcoin (свидетельская транзакция) (
tx.psbt), в которой расходуется одноразовая печать Алисы, модифицированная для включения криптографического обязательства перед Бобом.
На этом этапе транзакция еще не транслируется в сети Биткойн. Консигнация больше, чем базовая, поскольку включает всю историю (цепочку доказательств), подтверждающую легитимность актива.
8) Боб проверяет и принимает груз
Алиса передает эту терминальную партию Бобу. После этого Боб :
- Проверьте достоверность перехода состояния (убедитесь, что история последовательна, что правила контракта соблюдены и т.д.);
- Добавьте его в свой местный тайник;
- Возможно создание подписи (
sig:...) на отправлении, чтобы доказать, что оно было осмотрено и одобрено (иногда это называется "платежная ведомость").
bob$ rgb accept consignment.rgb
sig:DbwzvSu4BZU81jEpE9FVZ3xjcyuTKWWy2gmdnaxtACrS
9) Вариант: Боб отправляет Алисе подтверждение (платежную ведомость)
Если Боб захочет, он может отправить эту подпись обратно Алисе. Это означает:
- Что он признает переход действительным;
- Что он согласен с транзакцией Биткойн в эфире.
Это не является обязательным, но может дать Алисе уверенность в том, что впоследствии не возникнет споров по поводу передачи.
10) Алиса подписывает и публикует транзакцию
Алиса может :
- Проверьте подпись Боба (
rgb check <sig>) ; - Подпишите свидетельскую транзакцию, которая все еще является PSBT
(
подпись кошелька); - Опубликуйте транзакцию свидетеля в сети Биткойн (
-publish).
alice$ rgb check <sig>
alice$ wallet sign —publish tx.psbt
После подтверждения эта транзакция знаменует собой завершение передачи. Боб становится новым владельцем актива: теперь у него есть состояние Owned State, указывающее на контролируемый им UTXO, что подтверждается наличием обязательства в транзакции.
Вкратце, вот полный процесс перевода:
Преимущества передачи данных в формате RGB
- Конфиденциальность** :
Только Алиса и Боб имеют доступ ко всем данным о переходе состояний. Они обмениваются этой информацией вне блокчейна, через транзакции. Криптографические обязательства в транзакции Bitcoin не раскрывают ни тип актива, ни его количество, что гарантирует гораздо большую конфиденциальность, чем другие системы токенов на цепочке.
- Проверка на стороне клиента** :
Боб может проверить согласованность перевода, сравнив накладную с якорями в блокчейне Биткойна. Ему не нужно стороннее подтверждение. Алисе не нужно публиковать полную историю в блокчейне, что снижает нагрузку на базовый протокол и повышает конфиденциальность.
- Упрощенная атомарность** :
Сложные обмены (например, атомарный обмен между BTC и активом RGB) могут быть осуществлены в рамках одной транзакции, что избавляет от необходимости использовать скрипты HTLC или PTLC. Если соглашение не транслируется, каждый может повторно использовать свои UTXO другими способами.
Сводная диаграмма переноса
Прежде чем рассматривать счета более подробно, приведем краткую схему общего процесса передачи RGB:
- Боб устанавливает кошелек RGB и получает первоначальный контракт на поставку;
- Боб выставляет счет-фактуру с указанием UTXO, где нужно получить актив;
- Алиса получает счет-фактуру, создает PSBT и формирует терминальную партию;
- Боб принимает его, проверяет, добавляет данные в свой тайник и при необходимости подписывает (платежная ведомость);
- Алиса публикует транзакцию в сети Биткойн;
- Подтверждение сделки делает перевод официальным.
Этот перевод демонстрирует всю мощь и гибкость протокола RGB: частный обмен, подтвержденный на стороне клиента, минимально и незаметно привязанный к блокчейну Биткойна и сохраняющий все преимущества безопасности протокола (отсутствие риска двойной траты). Это делает RGB перспективной экосистемой для передачи ценностей, более конфиденциальной и масштабируемой, чем программируемые блокчейны на цепочке.
Счета-фактуры RGB
В этом разделе мы подробно расскажем, как инвойсы работают в экосистеме RGB и как они позволяют проводить операции (в частности, переводы) с контрактом. Сначала мы рассмотрим используемые идентификаторы, затем то, как они кодируются, и, наконец, структуру счета, выраженную в виде URL (формат, удобный для использования в кошельках).
Идентификаторы и кодирование
Для каждого из следующих элементов определяется уникальный идентификатор:
- Контракт RGB;
- Схема (бизнес-логика) ;
- Его интерфейс и реализация интерфейса ;
- Его активы (токены, NFT и т.д.),
Эта уникальность очень важна, поскольку каждый компонент системы должен быть различим. Например, контракт X нельзя спутать с другим контрактом Y, а два разных интерфейса (например, RGB20 против RGB21) должны иметь разные идентификаторы.
Чтобы сделать эти идентификаторы эффективными (небольшого размера) и читаемыми, мы используем :
- Кодировка Base58, которая позволяет избежать использования запутанных
символов (например,
0и буквыO) и создавать относительно короткие строки; - Префикс, указывающий на характер идентификатора, обычно в виде
rgb:или аналогичного URN.
Например, ContractId может быть представлен чем-то вроде :
rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX
Префикс rgb: подтверждает, что это RGB-идентификатор, а не HTTP-ссылка
или другой протокол. Благодаря этому префиксу кошельки могут правильно интерпретировать
строку.
Сегментация идентификаторов
Идентификаторы RGB часто бывают довольно длинными, так как для обеспечения
безопасности (криптографической) могут потребоваться поля длиной 256 бит и
более. Чтобы облегчить чтение и проверку человеком, мы разбиваем эти строки
на несколько блоков, разделенных дефисом (-). Таким образом,
вместо длинной, непрерывной строки символов мы делим ее на более короткие
блоки. Такая практика характерна для номеров кредитных карт или телефонов, и
здесь она также применяется для облегчения проверки. Так, например,
пользователю или партнеру можно сказать: "Пожалуйста, проверьте, что третий блок - 9GEgnyMj7", вместо того чтобы сравнивать все сразу. Последний блок часто
используется в качестве контрольной суммы, чтобы иметь
систему обнаружения ошибок или опечаток.
Например, ContractId в кодировке base58 и сегментированный может
быть :
2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX
Каждое из тире разбивает строку на части. Это не влияет на семантику кода, только на его представление.
Использование URL-адресов для счетов-фактур
RGB-счет представлен в виде URL-адреса. Это означает, что на него можно нажать или отсканировать (как QR-код), и кошелек сможет напрямую интерпретировать его для совершения транзакции. Такая простота взаимодействия отличается от некоторых других систем, где вам приходится копировать и вставлять различные данные в разные поля программы.
Счет-фактура для взаимозаменяемого токена (например, токена RGB20) может выглядеть следующим образом:
rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/RGB20/100+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb
Давайте проанализируем этот URL:
rgb:** (префикс): указывает на ссылку, вызывающую протокол RGB (аналогичноhttp:илиbitcoin:в других контекстах);2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX**: представляетContractIdтокена, которым вы хотите манипулировать;/RGB20/100**: указывает, что используется интерфейсRGB20и что запрашивается 100 единиц актива. Синтаксис следующий:/Интерфейс/сумма;+utxob:**: указывает, что добавляется информация о получателе UTXO (или, точнее, определение одноразовой печати);egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb**: это ослепленный UTXO (или определение печати). Другими словами, Боб замаскировал свой точный UTXO, так что отправитель (Алиса) не знает, каков его точный адрес. Она знает только, что существует действительная печать, ссылающаяся на UTXO, контролируемый Бобом.
Тот факт, что все укладывается в один URL, облегчает жизнь пользователю: простой клик или сканирование кошелька, и операция готова к выполнению.
Можно представить себе систему, в которой вместо ContractId используется простой тикер (например, USDT). Однако в этом
случае возникли бы серьезные проблемы с доверием и безопасностью: тикер не
является уникальной ссылкой (несколько контрактов могут претендовать на
название USDT). В RGB нам нужен уникальный, однозначный
криптографический идентификатор. Поэтому была принята 256-битная строка,
закодированная в base58 и сегментированная. Пользователь знает, что он
манипулирует именно тем контрактом, чей идентификатор 2WBcas9-yjz..., а не каким-либо другим.
Дополнительные параметры URL
Вы также можете добавить дополнительные параметры в URL, как и в HTTP, например :
rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/RGB20/100+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb?sig=6kzbKKffP6xftkxn9UP8gWqiC41W16wYKE5CYaVhmEve
?sig=...: представляет собой, например, подпись, связанную со счетом-фактурой, которую могут проверить некоторые кошельки;- Если кошелек не управляет этой подписью, он просто игнорирует этот параметр.
Рассмотрим случай NFT через интерфейс RGB21. Например, мы можем иметь :
rgb:7BKsac8-beMNMWA8r-3GEprtFh7-bjzEvGufY-aNLuU4nSN-MRsLOIK/RGB21/DbwzvSu-4BZU81jEp-E9FVZ3xj-cyuTKWWy-2gmdnaxt-ACrS+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb
Здесь мы видим :
rgb:**: Префикс URL ;7BKsac8-beMNMWA8r-3GEprtFh7-bjzEvGufY-aNLuU4nSN-MRsLOIK**: ID контракта (NFT) ;- rGB21**: интерфейс для неплатежеспособных активов (NFT) ;
DbwzvSu-4BZU81jEp-...**: явная ссылка на уникальную часть NFT, например, хэш блоба данных (медиа, метаданные...) ;+utxob:egXsFnw-...**: определение печати.
Идея та же: передайте уникальную ссылку, которую кошелек может интерпретировать, четко идентифицируя уникальный актив, подлежащий передаче.
Другие операции через URL
URL-адреса RGB используются не только для запроса перевода. Они также могут кодировать более сложные операции, такие как выпуск новых токенов (issuance). Например:
rgb:2WBcas9-yjzEvGufY-9GEgnyMj7-beMNMWA8r-sPHtV1nPU-TMsGMQX/RGB20/issue/100000+utxob:egXsFnw-5Eud7WKYn-7DVQvcPbc-rR69YmgmG-veacwmUFo-uMFKFb
Здесь мы находим :
rgb:: протокол ;2WBcas9-...: ID контракта ;/RGB20/issue/100000: указывает, что вы хотите вызвать переход "Issue" для создания дополнительных 100 000 жетонов;+utxob:: определение печати.
Например, кошелек может гласить: "Меня попросили выполнить операцию выдачи из интерфейса RGB20, по такому-то и такому-то контракту, на 100
000 единиц, в пользу такой-то и такой-то Одноразовой Печати*"
Теперь, когда мы рассмотрели основные элементы RGB-программирования, я расскажу вам в следующей главе о том, как составлять RGB-контракт.
Составление смарт-контрактов
В этой главе мы рассмотрим пошаговый подход к написанию контракта с помощью
инструмента командной строки rgb. Цель - показать, как
установить и работать с CLI, скомпилировать схему,
импортировать интерфейс и реализацию интерфейса, а затем выпустить (issue)
актив. Мы также рассмотрим базовую логику, включая компиляцию и проверку
состояния. К концу этой главы вы сможете воспроизвести этот процесс и
создать свои собственные RGB-контракты.
Напомним, что внутренняя логика RGB основана на библиотеках Rust, которые
вы, как разработчики, можете импортировать в свои проекты для управления
частью валидации на стороне клиента. Кроме того, команда LNP/BP Association
работает над привязками для других языков, но эта работа еще не завершена.
Кроме того, другие организации, такие как Bitfinex, разрабатывают свои
собственные интеграционные стеки (мы поговорим о них в последних двух главах
курса). Таким образом, на данный момент официальным эталоном является rgb CLI, даже если он остается относительно недоработанным.
Установка и презентация инструмента rgb
Основная команда называется просто rgb. Она напоминает git, с набором подкоманд для работы с контрактами, их вызовом,
выпуском активов и так далее. Bitcoin Wallet в настоящее время не
интегрирован, но будет интегрирован в ближайшей версии (0.11). Следующая
версия позволит пользователям создавать и управлять своими кошельками (через
дескрипторы) непосредственно из rgb, включая генерацию PSBT,
совместимость с внешним оборудованием (например, аппаратным кошельком) для
подписи и взаимодействие с таким программным обеспечением, как Sparrow. Это
упростит весь сценарий эмиссии и передачи активов.
Установка через Cargo
Мы устанавливаем инструмент в Rust с :
cargo install rgb-contracts --all-features
(Примечание: крейт называется rgb-contracts, а установленная
команда будет называться rgb. Если крейт с именем rgb уже существовал, могло произойти столкновение, отсюда и название)
При установке компилируется большое количество зависимостей (например, парсинг команд, интеграция Electrum, управление доказательствами нулевого знания и т. д.).
По завершении установки в меню :
rgb
Запуск rgb (без аргументов) выводит список доступных подкоманд,
таких как interfaces, chema, import, export, issue, invoice, transfer и т.д. Вы можете изменить директорию локального хранилища
(тайник, в котором хранятся все журналы, схемы и реализации), выбрать сеть (testnet,
mainnet) или настроить свой сервер Electrum.
Первый обзор элементов управления
Выполнив следующую команду, вы увидите, что интерфейс RGB20 уже
интегрирован по умолчанию:
rgb interfaces
Если этот интерфейс не интегрирован, клонируйте файл :
git clone https://github.com/RGB-WG/rgb-interfaces
Скомпилируйте его:
cargo run
Затем импортируйте выбранный вами интерфейс:
rgb import interfaces/RGB20.rgb
С другой стороны, нам говорят, что ни одна схема еще не была импортирована в программное обеспечение. Также нет контракта в тайнике. Чтобы увидеть его, выполните команду :
rgb schemata
Затем вы можете клонировать хранилище, чтобы получить определенные схемы:
git clone https://github.com/RGB-WG/rgb-schemata
Этот репозиторий содержит в директории src/ несколько файлов
Rust (например, nia.rs), которые определяют схемы (NIA для "Ненадуваемый актив", UDA для "Уникальный цифровой актив" и т.д.). Для компиляции
можно выполнить команду :
cd rgb-schemata
cargo run
В результате создается несколько файлов .rgb и .rgba, соответствующих скомпилированным схемам. Например, вы
найдете NonInflatableAsset.rgb.
Импорт схемы и реализации интерфейса
Теперь вы можете импортировать схему в rgb :
rgb import schemata/NonInflatableAssets.rgb
Это добавляет ее в локальный архив. Если мы выполним следующую команду, то увидим, что схема теперь появилась:
rgb schemata
Создание контракта (выдача)
Существует два подхода к созданию нового актива:
- Либо мы используем скрипт или код на Rust, который создает Контракт,
заполняя поля схемы (глобальное состояние, Владельческие состояния и т.д.)
и создавая файл
.rgbили.rgba; - Или используйте подкоманду
issueнапрямую, с файлом YAML (или TOML), описывающим свойства токена.
Вы можете найти примеры в Rust в папке examples, которые
иллюстрируют, как вы создаете ContractBuilder, заполняете глобальное состояние (имя актива, тикер, поставка, дата и т.д.), определяете Owned State (к
какому UTXO он приписан), затем собираете все это в contract consignment, который вы можете экспортировать, подтвердить
и импортировать в тайник.
Другой способ - вручную отредактировать YAML-файл, чтобы настроить ticker, name, upply и так далее. Предположим, файл
называется RGB20-demo.yaml. Вы можете указать :
spec: тикер, название, точность ;термы: поле для юридических уведомлений ;Выпущенный запас: количество выпущенных токенов;Назначения: указывает на одноразовую пломбу (определение пломбы) и разблокированное количество.
Вот пример YAML-файла, который нужно создать:
interface: RGB20Fixed
globals:
spec:
ticker: PBN
name: Plan B Network
details: "Pay attention: the asset has no value"
precision: 2
terms:
text: >
SUBJECT TO, AND WITHOUT IN ANY WAY LIMITING, THE REPRESENTATIONS AND WARRANTIES OF ANY SELLER. PROPERTY IS BEING SOLD “AS IS”...
media: ~
issuedSupply: 100000000
assignments:
assetOwner:
seal: tapret1st:b449f7eaa3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1
amount: 100000000 # this is 1 million (we have two digits for cents)
Затем просто выполните команду :
rgb issue '<SchemaID>' ssi:<Issuer> rgb20-demo.yaml
В моем случае уникальный идентификатор схемы (должен быть заключен в
одинарные кавычки) - RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k, и я не указал эмитента. Итак, мой заказ: :
rgb issue 'RDYhMTR!9gv8Y2GLv9UNBEK1hcrCmdLDFk9Qd5fnO8k' ssi:anonymous rgb20-demo.yaml
Если вы не знаете идентификатор схемы, выполните команду :
rgb schemata
CLI отвечает, что новый контракт был выпущен и добавлен в тайник. Если мы введем следующую команду, то увидим, что теперь есть дополнительный контракт, соответствующий только что выпущенному:
rgb contracts
Затем следующая команда выводит глобальные состояния (имя, тикер,
предложение...) и список Owned States, то есть распределений (например, 1
миллион токенов PBN, определенных в UTXO b449f7eaa3f98c145b27ad0eeb7b5679ceb567faef7a52479bc995792b65f804:1).
rgb state '<ContractId>'
Экспорт, импорт и проверка
Чтобы поделиться этим контрактом с другими пользователями, его можно экспортировать из тайника в файл :
rgb export '<ContractId>' myContractPBN.rgb
Файл myContractPBN.rgb может быть передан другому пользователю,
который может добавить его в свой тайник с помощью команды :
rgb import myContractPBN.rgb
При импорте, если это простая контрактная партия, мы получим
сообщение "Importing consignment rgb". Если это более крупная переходная партия, команда будет другой (rgb accept).
Для обеспечения достоверности можно также использовать локальную функцию проверки. Например, можно выполнить команду :
rgb validate myContract.rgb
Использование, проверка и отображение тайников
Напомним, что тайник - это локальный список схем, интерфейсов, реализаций и контрактов (Genesis + переходы). Каждый раз, когда вы выполняете команду "import", вы добавляете элемент в тайник. Этот тайник можно просмотреть в деталях с помощью команды :
rgb dump
В результате будет создана папка с подробной информацией обо всем тайнике.
Трансфер и PSBT
Чтобы осуществить перевод, вам потребуется манипулировать локальным
кошельком Bitcoin для управления обязательствами Tapret или Opret.
Создайте счет-фактуру
В большинстве случаев взаимодействие между участниками контракта (например, Алисой и Бобом) происходит через создание счета-фактуры. Если Алиса хочет, чтобы Боб что-то выполнил (передачу токена, перевыпуск, действие в DAO и т. д.), Алиса создает счет-фактуру, в котором подробно описывает свои инструкции Бобу. Таким образом, мы имеем :
- Алиса** (эмитент счета-фактуры) ;
- Боб** (который получает и исполняет счет-фактуру).
В отличие от других экосистем, RGB-счет не ограничивается понятием оплаты. Он может содержать любой запрос, связанный с контрактом: отозвать ключ, проголосовать, создать гравировку (engraving) на NFT и т. д. Соответствующая операция может быть описана в интерфейсе контракта. Соответствующая операция может быть описана в интерфейсе контракта.
Следующая команда генерирует RGB-фактуру:
$ rgb invoice $CONTRACT -i $INTERFACE $ACTION $STATE $SEAL
С :
$CONTRACT: Идентификатор контракта (ContractId) ;$INTERFACE: интерфейс, который будет использоваться (например,RGB20) ;$ACTION: имя операции, указанной в интерфейсе (для простой передачи сменного токена это может быть "Transfer"). Если интерфейс уже предоставляет действие по умолчанию, вам не нужно вводить его здесь снова;$STATE: данные о состоянии, которые будут переданы (например, количество токенов, если передается сменный токен);$SEAL: одноразовая печать получателя (Алисы), т.е. явная ссылка на UTXO. Боб использует эту информацию для создания транзакции-свидетеля, и соответствующий выход будет принадлежать Алисе (в ослепленном UTXO или незашифрованном виде).
Например, с помощью следующих команд
alice$ CONTRACT='iZgIN9EL-2H21UgQ-x!A3uJc-WwXhCSm-$9Lwcc1-v!mUkKY'
alice$ MY_UTXO=4960acc21c175c551af84114541eace09c14d3a1bb184809f7b80916f57f9ef8:1
alice$ rgb invoice $CONTRACT -i RGB20 --amount 100 $MY_UTXO
CLI создаст счет-фактуру, как :
rgb:iZgIN9EL-2H21UgQ-x!A3uJc-WwXhCSm-$9Lwcc1-v!mUkKY/RGB20/100+utxob:zlVS28Rb-...
Она может быть передана Бобу по любому каналу (текст, QR-код и т. д.).
Осуществление перевода
Для переноса из этого счета :
- У Боба (который хранит токены в своем тайнике) есть кошелек Bitcoin. Ему
необходимо подготовить транзакцию Bitcoin (в форме PSBT, например
tx.psbt), которая расходует UTXO, где находятся необходимые токены RGB, плюс один UTXO для валюты (обмена); - Боб выполняет следующую команду:
bob$ rgb transfer tx.psbt $INVOICE consignment.rgb
- В результате создается файл
consignment.rgb, который содержит : - История перехода доказывает Алисе, что токены подлинные;
- Новый переход, передающий жетоны на одноразовую печать Алисы;
- Транзакция свидетеля (без знака).
- Боб отправляет этот файл
consignment.rgbАлисе (по электронной почте, через сервер совместного доступа или протокол RGB-RPC, Storm и т. д.); - Алиса получает
consignment.rgbи принимает его в свой тайник:
alice$ rgb accept consignment.rgb
- CLI проверяет валидность перехода и добавляет его в тайник Алисы. Если он недействителен, команда завершается неудачей с подробным сообщением об ошибке. В противном случае она завершается успешно и сообщает, что пример транзакции еще не был передан в сеть Биткойн (Боб ждет зеленого света от Алисы);
- В качестве подтверждения команда
acceptвозвращает подпись (payslip), которую Алиса может отправить Бобу, чтобы показать ему, что она подтвердила назначение; - Затем Боб может подписать и опубликовать (
--publish) свою транзакцию Bitcoin:
bob$ rgb check <sig> && wallet sign --publish tx.psbt
- Как только эта транзакция подтверждается на цепочке, право собственности на актив считается переданным Алисе. Кошелек Алисы, следящий за майнингом транзакции, видит, как в его тайнике появляется новое состояние Owned State.
В следующей главе мы подробно рассмотрим интеграцию RGB в Lightning Network.
RGB в сети Lightning
В этой главе я предлагаю рассмотреть, как RGB можно использовать в сети Lightning Network для интеграции и перемещения активов RGB (токенов, NFT и т. д.) через внецепочечные платежные каналы.
Основная идея заключается в том, что переход состояния RGB (State Transition) может быть зафиксирован в транзакции Bitcoin, которая, в свою очередь, может оставаться вне цепи до тех пор, пока канал Lightning не будет закрыт. Таким образом, каждый раз, когда канал обновляется, новый переход состояния RGB может быть включен в новую фиксирующую транзакцию, которая затем аннулирует старый переход. Таким образом, каналы Lightning могут использоваться для передачи активов RGB и могут быть направлены так же, как и обычные платежи Lightning.
Создание и финансирование каналов
Чтобы создать канал Lightning, передающий RGB-активы, нам понадобятся два элемента:
- Биткойн-финансирование для создания мультисига канала 2/2 (основной UTXO для канала);
- Финансирование RGB, которое отправляет активы в тот же мультисиг.
В терминах Биткойна транзакция финансирования должна существовать для
определения эталонного UTXO, даже если она содержит лишь небольшое
количество сатов (при этом каждый вывод в будущих транзакциях обязательств
должен оставаться выше лимита пыли). Например, Алиса может решить
предоставить 10 тыс. сатов и 500 USDT (выпущенных в виде актива RGB). В
транзакцию финансирования мы добавляем обязательство (Opret или Tapret), которое закрепляет переход состояния RGB.
После того как транзакция финансирования подготовлена (но еще не передана), создаются транзакции обязательств, чтобы любая из сторон могла закрыть канал в одностороннем порядке в любой момент. Эти транзакции похожи на классические транзакции обязательств Lightning, за исключением того, что мы добавляем дополнительный выход, содержащий RGB-якорь (OP_RETURN или Taproot), связанный с новым переходом состояния.
Затем переход в состояние RGB перемещает активы из мультисигмы 2/2 финансирования в выходы транзакции обязательств. Преимущество этого процесса в том, что безопасность состояния RGB в точности соответствует карательной механике Lightning: если Боб передаст старое состояние канала, Алиса может наказать его и потратить выход, чтобы вернуть и саты, и токены RGB. Таким образом, стимул даже сильнее, чем в канале Lightning без RGB-активов, поскольку атакующий может потерять не только sats, но и RGB-активы канала.
Таким образом, транзакция с обязательствами, подписанная Алисой и отправленная Бобу, будет выглядеть следующим образом:
А сопровождающая транзакция с обязательствами, подписанная Бобом и отправленная Алисе, будет выглядеть следующим образом:
Обновление канала
Когда между двумя участниками канала происходит платеж (или они хотят изменить распределение активов), они создают новую пару транзакций обязательств. Сумма в сатах на каждом выходе может оставаться или не оставаться неизменной, в зависимости от реализации, поскольку ее основная роль заключается в том, чтобы обеспечить построение действительных UTXO. С другой стороны, выход OP_RETURN (или Taproot) должен быть изменен, чтобы содержать новый якорь RGB, представляющий новое распределение активов в канале.
Например, если Алиса переводит 30 USDT Бобу по каналу, новый переход состояния будет отражать баланс в 400 USDT для Алисы и 100 USDT для Боба. Транзакция фиксации добавляется в якорь OP_RETURN/Taproot (или модифицируется им), чтобы включить этот переход. Обратите внимание, что, с точки зрения RGB, входом для перехода остается исходный мультисиг (в котором активы на цепи фактически распределяются до закрытия канала). Меняются только выходы RGB (распределения), в зависимости от принятого решения о перераспределении.
Транзакция с обязательствами, подписанная Алисой, готова к распространению Бобом:
Транзакция с обязательствами, подписанная Бобом, готова к распространению Алисой:
Управление HTLC
В действительности Lightning Network позволяет направлять платежи по нескольким каналам, используя HTLC (Hashed Time-Locked Contracts). То же самое происходит и с RGB: для каждого платежа, проходящего по каналу, к транзакции, совершающей транзакцию, добавляется выход HTLC, а к этому HTLC привязывается распределение RGB. Таким образом, тот, кто потратит HTLC-вывод (благодаря секрету или по истечении таймлока), получит и саты, и связанные с ними RGB-активы. С другой стороны, вам, очевидно, нужно иметь достаточно денег на дороге в виде как сатов, так и RGB-активов.
Поэтому работу RGB на Lightning следует рассматривать параллельно с работой самой сети Lightning. Если вы хотите углубиться в эту тему, я настоятельно рекомендую вам взглянуть на другой обширный учебный курс:
https://planb.network/courses/34bd43ef-6683-4a5c-b239-7cb1e40a4aeb
Карта кодов RGB
Наконец, прежде чем перейти к следующему разделу, я хотел бы дать вам обзор кода, используемого в RGB. Протокол основан на наборе библиотек Rust и спецификаций с открытым исходным кодом. Вот обзор основных репозиториев и крейтов:
Удостоверение на стороне клиента
- Репозиторий**: client_side_validation
- Крейты** : client_side_validation, single_use_seals
Управление валидацией вне цепи и логикой одноразовых печатей.
Детерминированные обязательства биткойна (DBC)
Управление детерминированными привязками в транзакциях Bitcoin (Tapret, OP_RETURN и т. д.).
Многопротокольное обязательство (MPC)
- Репозиторий**: client_side_validation
- Крейт** : commit_verify
Многочисленные комбинации задействования и интеграция с различными протоколами.
Строгие типы и строгое кодирование
- Спецификации**: веб-сайт strict-types.org
- Репозитории**: strict-types, strict-encoding
- Крейты** : strict_types, strict_encoding
Строгая система типизации и детерминированная сериализация используются для проверки на стороне клиента.
Ядро RGB
Ядро протокола, которое включает в себя основную логику проверки RGB.
Стандартная библиотека и кошелек RGB
Стандартные реализации, управление тайниками и кошельками.
RGB CLI
- Репозиторий**: rgb
- Ящики**: rgb-cli, rgb-wallet
CLI rgb и crate wallet для работы с контрактами в командной строке.
Схема RGB
- Репозиторий**: rgb-schemata
Содержит примеры схем (NIA, UDA и т.д.) и их реализаций.
ALuVM
- Информация** : aluvm.org
- Репозитории**: aluvm-spec, alure
- Ящики**: aluvm, aluasm
Виртуальная машина на основе реестра, используемая для запуска сценариев проверки.
Протокол биткойна - BP
Дополнения для поддержки протокола Bitcoin (транзакции, обходы и т. д.).
Повсеместные детерминированные вычисления - UBIDECO
- Репозиторий**: UBIDECO
Экосистема, связанная с детерминированными разработками с открытым исходным кодом.
Построение на основе RGB
DIBA и проект Bitmask
Этот заключительный раздел курса основан на презентациях, сделанных различными докладчиками на буткампе RGB. Он включает в себя отзывы и размышления о RGB и его экосистеме, а также презентации инструментов и проектов, основанных на протоколе. Модератором первой главы выступает Хантер Бист, а двух последующих - Фредерико Тенга.
От JavaScript к Rust и в экосистему биткойна
Сначала Хантер Бист работал в основном на JavaScript. Затем он открыл для себя Rust, синтаксис которого поначалу показался ему непривлекательным и разочаровывающим. Однако потом он оценил мощь языка, контроль над памятью (heap и stack), а также безопасность и производительность. Он подчеркивает, что Rust - это отличная тренировочная база для глубокого понимания того, как работает компьютер.
Хантер Бист рассказывает о своем участии в различных проектах экосистемы altcoin, таких как Ethereum (с Solidity, TypeScript и т. д.), а затем Filecoin. Он объясняет, что поначалу некоторые протоколы произвели на него впечатление, но в итоге большинство из них его разочаровали, не в последнюю очередь из-за их токеномики. Он осуждает сомнительные финансовые стимулы, инфляционное создание токенов, которое размывает инвесторов, и потенциально эксплуататорский аспект этих проектов. В итоге он занял позицию Биткойн-максималиста, не в последнюю очередь потому, что некоторые люди открыли ему глаза на более разумные экономические механизмы Биткойна и на надежность этой системы.
Привлекательность RGB и создание слоев
По его словам, окончательно убедить его в актуальности биткоина удалось благодаря открытию RGB и концепции слоев. Он считает, что существующие в других блокчейнах функции могут быть воспроизведены на более высоких уровнях, выше биткойна, без изменения базового протокола.
В феврале 2022 года он присоединился к DIBA для работы над RGB, и в частности над кошельком Bitmask. В то время Bitmask был еще в версии 0.01, а RGB работал в версии 0.4, только для управления одиночными токенами. Он отмечает, что это было менее ориентировано на самообеспечение, чем сегодня, поскольку логика была частично серверной. С тех пор архитектура развивалась в направлении этой модели, что очень ценится биткойнерами.
Основы протокола RGB
Протокол RGB является самым последним и наиболее продвинутым воплощением концепции цветных монет, которая уже исследовалась примерно в 2012-2013 годах. В то время несколько команд пытались привязать различные биткоины к UTXO, что привело к появлению множества разрозненных реализаций. Отсутствие стандартизации и низкий спрос в то время не позволили этим решениям закрепиться надолго.
Сегодня RGB выделяется своей концептуальной устойчивостью и унифицированными спецификациями через ассоциацию LNP/BP. Принцип основан на валидации на стороне клиента. В блокчейне Bitcoin хранятся только криптографические обязательства (commitments, через Taproot или OP_RETURN), в то время как большая часть данных (определения контрактов, истории переводов и т. д.) хранится у соответствующих пользователей. Таким образом, нагрузка на хранилище распределяется, а конфиденциальность обмена укрепляется, не утяжеляя блокчейн. Такой подход позволяет создавать взаимозаменяемые активы (стандарт RGB20) или уникальные активы (стандарт RGB21) в рамках модульной и масштабируемой структуры.
Функция токена (RGB20) и уникальные активы (RGB21)
С помощью RGB20 мы определяем взаимозаменяемый токен в Биткойне. Эмитент выбирает поставку, точность и создает контракт, по которому он может осуществлять переводы. Каждый перевод ссылается на биткойн UTXO, который действует как пломба одноразового использования. Эта логика гарантирует, что пользователь не сможет потратить один и тот же актив дважды, поскольку только тот, кто способен потратить UTXO, на самом деле владеет ключом для обновления состояния контракта на стороне клиента.
RGB21 нацелены на уникальные активы (или "NFT"). Актив имеет запас 1 и может быть связан с метаданными (файл изображения, аудио и т. д.), описанными через определенное поле. В отличие от NFT на публичных блокчейнах, данные и их MIME-идентификаторы могут оставаться приватными, распространяясь между пирами по усмотрению владельца.
Решение Bitmask: кошелек для RGB
Чтобы использовать возможности RGB на практике, проект DIBA разработал кошелек под названием Bitmask. Идея состоит в том, чтобы предоставить инструмент на базе Taproot, не требующий хранения, доступный в виде веб-приложения или расширения для браузера. Bitmask управляет активами RGB20 и RGB21 и интегрирует различные механизмы безопасности:
- Основной код написан на Rust, затем скомпилирован в WebAssembly для запуска в среде JavaScript (React);
- Ключи генерируются локально, затем хранятся в зашифрованном виде локально;
- Данные состояния (stash) хранятся в памяти, сериализуются и шифруются с помощью библиотеки Carbonado, которая выполняет сжатие, коррекцию ошибок, шифрование и проверку потока с помощью Blake3.
Благодаря такой архитектуре все транзакции с активами происходят на стороне клиента. Со стороны транзакция биткоина представляет собой не что иное, как классическую транзакцию по расходованию средств Taproot, о которой никто не заподозрит, что она также несет в себе перевод сменных токенов или NFT. Отсутствие перегрузки на цепочке (отсутствие публично хранимых метаданных) гарантирует определенную степень конфиденциальности и позволяет легче противостоять возможным попыткам цензуры.
Безопасность и распределенная архитектура
Поскольку протокол RGB требует, чтобы каждый участник сохранял историю своих транзакций (для подтверждения достоверности полученных им переводов), возникает вопрос о хранении. Bitmask предлагает сериализовать этот тайник локально, а затем отправлять его на несколько серверов или облаков (по желанию). Данные остаются зашифрованными пользователем через Carbonado, поэтому сервер не сможет их прочитать. В случае частичного повреждения слой коррекции ошибок может восстановить содержимое.
Использование CRDT (Conflict-free replicated data type) позволяет объединять различные версии тайника, если они расходятся. Каждый волен размещать эти данные там, где ему заблагорассудится, поскольку ни один узел не несет в себе всю информацию, связанную с активом. Это в точности отражает философию Client-side Validation, где каждый владелец отвечает за хранение доказательств достоверности своего RGB-актива.
На пути к расширению экосистемы: рынок, совместимость и новые функции
Компания, стоящая за Bitmask, не ограничивается простой разработкой кошелька. DIBA намерена разработать :
- Место рынка для обмена токенами, особенно в форме RGB21;
- Совместимость с другими кошельками (например, Iris Wallet);
- Техника пакетной передачи**, т.е. возможность включения нескольких последовательных RGB-передач в одну транзакцию.
В то же время мы работаем над WebBTC или WebLN (стандарты, позволяющие веб-сайтам просить кошелек подписывать транзакции Bitcoin или Lightning), а также над возможностью "телеобжига" записей Ordinals (если мы хотим перевести Ordinals в более сдержанный и гибкий формат RGB).
Заключение
Весь процесс показывает, как экосистема RGB может быть развернута и доступна для конечных пользователей с помощью надежных технических решений. Переход от перспективы альткоинов к более ориентированному на Биткоин видению, в сочетании с открытием Client-side Validation, иллюстрирует довольно логичный путь: мы понимаем, что можно реализовать различные функциональные возможности (сменные токены, NFT, смарт-контракты...) без форка блокчейна, просто используя преимущества криптографических обязательств в транзакциях Taproot или OP_RETURN.
Кошелек Bitmask является частью этого подхода: со стороны блокчейна все, что вы видите, - это обычная транзакция Bitcoin; со стороны пользователя вы управляете веб-интерфейсом, где создаете, обмениваете и храните все виды внецепочечных активов. Эта модель четко отделяет денежную инфраструктуру (Bitcoin) от логики эмиссии и передачи (RGB), обеспечивая при этом высокий уровень конфиденциальности и лучшую масштабируемость.
Работа Bitfinex над RGB
В этой главе, основанной на презентации Фредерико Тенга, мы рассмотрим набор инструментов и проектов, созданных командой Bitfinex, посвященных RGB, с целью способствовать возникновению богатой и разнообразной экосистемы вокруг этого протокола. Первоначальной целью команды является не выпуск конкретного коммерческого продукта, а предоставление программных блоков, вклад в сам протокол RGB и предложение конкретных примеров реализации, таких как мобильный кошелек (Iris Wallet) или совместимая с RGB нода Lightning.
Предпосылки и цели
Начиная примерно с 2022 года, команда Bitfinex RGB сосредоточилась на разработке технологического стека, который позволяет эффективно использовать и тестировать RGB. Было сделано несколько вкладов:
- Участие в разработке исходного кода и спецификаций протоколов, включая написание предложений по улучшению, исправление ошибок и т.д;
- Инструменты для разработчиков, упрощающие интеграцию RGB в их приложения;
- Дизайн мобильного кошелька под названием Iris для экспериментов и иллюстрации лучших практик использования RGB;
- Создание специализированного узла Lightning, способного управлять каналами с RGB-активами;
- Поддержка других команд, создающих решения на базе RGB, для поощрения разнообразия и создания сильной экосистемы.
Этот подход призван охватить всю цепочку потребностей: от низкоуровневой библиотеки (RGBlib), позволяющей реализовать кошелек, до производственного аспекта (узел Lightning, кошелек для Android и т.д.).
Библиотека RGBlib: упрощение разработки RGB-приложений
Важным моментом в демократизации создания RGB-кошельков и приложений является создание достаточно простой абстракции, чтобы разработчикам не приходилось изучать всю внутреннюю логику протокола. Именно эту цель преследует RGBlib, написанный на языке Rust.
RGBlib выступает в роли моста между очень гибкими (но иногда сложными) требованиями RGB, которые мы изучили в предыдущих главах, и конкретными потребностями разработчика приложений. Другими словами, кошелек (или сервис), желающий управлять передачей токенов, выпуском активов, верификацией и т. д., может полагаться на RGBlib, не зная всех криптографических деталей или всех настраиваемых параметров RGB.
Книжный магазин предлагает :
- Функции "под ключ" для выпуска (эмиссии) активов (взаимозаменяемых или нет);
- Возможность передавать (отправлять/получать) активы, манипулируя простыми объектами (адреса, суммы, UTXO и т.д.);
- Механизм для хранения и загрузки информации о состоянии (согласования), необходимой для проверки на стороне клиента.
Таким образом, RGBlib опирается на сложные понятия, характерные для RGB (проверка на стороне клиента, якоря Tapret/Opret), но инкапсулирует их так, что конечному приложению не нужно перепрограммировать все или принимать рискованные решения. Более того, RGBlib уже привязан к нескольким языкам (Kotlin и Python), что открывает возможности для использования за пределами простой вселенной Rust.
Iris Wallet: пример RGB-кошелька на Android
Чтобы доказать эффективность RGBlib, команда Bitfinex разработала Iris Wallet, на данном этапе исключительно для Android. Это мобильный кошелек, который иллюстрирует пользовательский опыт, схожий с обычным биткойн-кошельком: вы можете выпустить актив, отправить его, получить его, просмотреть его историю, оставаясь при этом в модели самоохраны.
Iris обладает рядом интересных особенностей:
Использование сервера Electrum:
Как и любому другому кошельку, Iris необходимо знать о подтверждении транзакций в блокчейне. Вместо того чтобы встраивать полноценный узел, Iris по умолчанию использует сервер Electrum, поддерживаемый командой Bitfinex. Однако пользователи могут настроить свой собственный сервер или другой сторонний сервис. Таким образом, транзакции биткоина можно проверять и извлекать информацию (индексировать) по модульному принципу.
Прокси-сервер RGB:
В отличие от Биткойна, RGB требует обмена метаданными вне цепочки (согласованиями) между отправителем и получателем. Чтобы упростить этот процесс, Iris предлагает решение, при котором обмен происходит через прокси-сервер. Получающий кошелек генерирует инвойс, в котором указывается, куда отправитель должен отправить данные клиентской стороны. По умолчанию URL указывает на прокси-сервер, размещенный командой Bitfinex, но вы можете изменить этот прокси-сервер (или разместить свой собственный). Идея заключается в том, чтобы вернуться к привычному пользовательскому опыту, когда получатель показывает QR-код, а отправитель сканирует этот код для проведения транзакции, без каких-либо сложных дополнительных манипуляций.
** Непрерывное резервное копирование:**
В контексте Биткойна обычно достаточно сохранить резервную копию семян (хотя в наши дни мы рекомендуем сохранять семена и дескрипторы). В случае с RGB этого недостаточно: вам также необходимо хранить локальную историю (консигнации), доказывающую, что вы действительно владеете активом RGB. Каждый раз, когда вы получаете чек, устройство сохраняет новые данные, которые необходимы для последующих трат. Iris автоматически управляет зашифрованной резервной копией в Google Drive пользователя. Это не требует особого доверия к Google, поскольку резервная копия зашифрована, а в будущем планируется использовать более надежные опции (например, персональный сервер), чтобы избежать риска цензуры или удаления сторонним оператором.
*Другие особенности:
- Создайте кран для быстрого тестирования или распространения жетонов для экспериментов или продвижения;
- Система сертификации (в настоящее время централизованная), позволяющая отличить легитимный токен от поддельного, копирующего известный тикер. В будущем эта сертификация может стать более децентрализованной (через DNS или другие механизмы).
В целом, Iris предлагает пользовательский опыт, близкий к классическому кошельку Bitcoin, маскируя дополнительные сложности (управление тайниками, история отправок и т. д.) благодаря RGBlib и использованию прокси-сервера.
Прокси-сервер и пользовательский опыт
Прокси-сервер, представленный выше, заслуживает подробного описания, поскольку он является ключом к бесперебойной работе пользователей. Вместо того чтобы отправителю вручную передавать конфигурации получателю, RGB-транзакция происходит в фоновом режиме через прокси-сервер :
- Получатель формирует инвойс (содержащий, помимо прочего, адрес прокси);
- Отправитель посылает (через HTTP-запрос) проект перехода (назначение) прокси-серверу;
- Получатель получает этот проект, выполняет проверку на стороне клиента локально;
- Затем получатель публикует через прокси-сервер сообщение о принятии (или, возможно, отклонении) перехода состояния;
- Отправитель может просмотреть статус проверки и, если он принят, транслировать транзакцию Bitcoin, завершая перевод.
Таким образом, кошелек ведет себя почти как обычный кошелек. Пользователь не знает обо всех промежуточных шагах. Конечно, текущий прокси не зашифрован и не аутентифицирован (что оставляет сомнения в конфиденциальности и целостности), но эти улучшения возможны в последующих версиях. Концепция прокси остается чрезвычайно полезной для воссоздания опыта "я отправляю QR-код, вы сканируете, чтобы заплатить".
Интеграция RGB в сеть Lightning
Еще одно ключевое направление работы команды Bitfinex - сделать сеть Lightning Network совместимой с активами RGB. Цель состоит в том, чтобы сделать возможными каналы Lightning в USDT (или любом другом токене) и воспользоваться теми же преимуществами, что и биткоин в Lightning (почти мгновенные транзакции, маршрутизация и т. д.). Если говорить конкретно, то это предполагает создание узла Lightning, модифицированного под :
- Откройте канал, разместив не только сатоши, но и один или несколько RGB-активов в финансирующем мультисиге UTXO;
- Генерируйте транзакции обязательств Lightning (со стороны Биткойна), сопровождаемые соответствующими переходами состояния RGB. Каждый раз, когда канал обновляется, RGB-переход переопределяет распределение активов в выходах Lightning;
- Возможность одностороннего закрытия, когда актив извлекается в эксклюзивном UTXO, в соответствии с правилами Lightning Network (HTLC, блокировка по времени, наказание и т. д.).
Это решение, получившее название "RGB Lightning Node",
использует LDK (Lightning Dev Kit) в качестве основы и добавляет
механизмы, необходимые для внедрения RGB-токенов в каналы. Lightning-коммиты
сохраняют классическую структуру (пробиваемые выходы, таймлок...), а также
дополнительно закрепляют переход в состояние RGB (через Opret или Tapret). Для пользователя это открывает путь к
Lightning-каналам в стабильных монетах или в любом другом активе,
эмитированном через RGB.
Потенциал DEX и влияние на биткойн
Когда несколько активов управляются через Lightning, становится возможным представить атомарную биржу на одном маршруте Lightning, используя ту же логику секретов и таймлоков. Например, пользователь A держит биткоин на одном канале Lightning, а пользователь B держит USDT RGB на другом канале Lightning. Они могут построить путь, соединяющий два их канала, и одновременно обменивать BTC на USDT, не нуждаясь в доверии. Это не что иное, как атомарный обмен, происходящий в несколько хопов, благодаря чему внешние участники практически не замечают, что совершают сделку, а не просто маршрутизацию. Этот подход предлагает :
- Очень низкая задержка, поскольку в Lightning все остается вне цепи.
- Превосходная приватность: никто не знает, что это торговля, а не обычная маршрутизация;
- Избежать опережения - постоянная проблема для DEX на цепочке;
- Сокращение расходов (вы не платите за блокчейн, только за маршрутизацию Lightning).
Мы можем представить себе экосистему, в которой узлы Lightning предлагают своп-цены (обеспечивая ликвидность). Каждый узел, если пожелает, может играть роль маркет-мейкера, покупая и продавая различные активы на Lightning. Эта перспектива DEX второго уровня подкрепляет идею о том, что для создания децентрализованных бирж активов не обязательно делать форки или использовать сторонние блокчейны.
Влияние на биткойн может быть положительным: Инфраструктура Lightning (узлы, каналы и сервисы) будет более полно загружена благодаря объемам, генерируемым этими стабильными монетами, деривативами и другими токенами. Торговцы, заинтересованные в платежах USDT на Lightning, механически обнаружат платежи BTC на Lightning (управляемые тем же стеком). Обслуживание и финансирование инфраструктуры Lightning Network также может выиграть от увеличения этих не-BTC потоков, что косвенно принесет пользу пользователям Биткойна.
Заключение и ресурсы
Команда Bitfinex, занимающаяся RGB, своей работой иллюстрирует разнообразие возможностей, которые можно реализовать на базе этого протокола. С одной стороны, есть RGBlib, библиотека, облегчающая разработку кошельков и приложений. С другой - Iris Wallet, практическая демонстрация на Android изящного интерфейса для конечного пользователя. Наконец, интеграция RGB с Lightning показывает, что каналы стабильных монеток возможны, и открывает путь к потенциальному децентрализованному DEX на Lightning.
Этот подход остается в значительной степени экспериментальным и продолжает развиваться: библиотека RGBlib дорабатывается по ходу дела, Iris Wallet получает регулярные улучшения, а выделенная нода Lightning пока не является основным клиентом Lightning.
Для тех, кто хочет узнать больше или внести свой вклад, есть несколько ресурсов, включая :
- Репозитории GitHub RGB Tools;
- Информационный сайт, посвященный Iris Wallet, чтобы протестировать кошелек на Android.
В следующей главе мы подробно рассмотрим, как запустить узел RGB Lightning.
RLN - RGB Lightning Node
В этой заключительной главе Фредерико Тенга шаг за шагом проведет вас через настройку узла Lightning RGB в среде Regtest и покажет, как создавать на нем токены RGB. Запустив два отдельных узла, вы также узнаете, как открыть между ними канал Lightning и обмениваться активами RGB.
Это видео является учебным пособием, аналогичным тому, что мы рассматривали в предыдущей главе, но в этот раз оно посвящено именно Lightning!
Основным ресурсом для этого видео является репозиторий Github RGB Lightning Node, который позволяет легко запустить эту конфигурацию в Regtest.
Развертывание узла Lightning, совместимого с RGB
В ходе этого процесса на практике реализуются все концепции, рассмотренные в предыдущих главах:
- Идея о том, что UTXO, заблокированный на 2/2 мультисиге канала Lightning, может получать не только биткоины, но и быть одноразовой печатью активов RGB (взаимозаменяемых или нет);
- Добавление в каждую транзакцию Lightning engagement выхода (
TapretилиOpret), предназначенного для закрепления перехода в состояние RGB; - Соответствующая инфраструктура (bitcoind/indexer/proxy) для подтверждения транзакций Bitcoin и обмена данными клиентской стороны.
Представляем rgb-lightning-node
Проект rgb-lightning-node представляет собой
демон Rust, основанный на форке rust-lightning (LDK), модифицированном
для учета наличия RGB-активов в канале. При открытии канала можно указать наличие
активов, и при каждом обновлении состояния канала создается RGB-переход, отражающий
распределение актива в выходах Lightning. Это позволяет :
- Откройте каналы Lightning в USDT, например;
- Маршрутизация этих токенов по сети при условии, что маршруты маршрутизации обладают достаточной ликвидностью;
- Используйте логику наказаний и блокировки времени Lightning без изменений: просто закрепите RGB-переход в дополнительном выходе транзакции обязательств.
Код все еще находится на стадии альфа-версии: мы рекомендуем использовать его только в regtest или в testnet.
Установка узла
Чтобы скомпилировать и установить бинарный файл rgb-lightning-node, мы начнем с клонирования репозитория и его подмодулей, а затем запустим
команду :
git clone https://github.com/RGB-Tools/rgb-lightning-node --recurse-submodules --shallow-submodules
- Опция
--recurse-submodulesтакже клонирует необходимые суб-устройства (включая модифицированную версиюrust-lightning); - Опция
--shallow-submodulesограничивает глубину клона для ускорения загрузки, но при этом предоставляет доступ к основным коммитам.
Из корня проекта выполните следующую команду для компиляции и установки двоичного файла :
cargo install --locked --debug --path .
--lockedгарантирует, что версия зависимостей строго соблюдается;--debugне является обязательным, но может помочь вам сосредоточиться (вы можете использовать--release, если хотите) ;--path .указываетcargo installна установку из текущего каталога.
По завершении этой команды в каталоге $CARGO_HOME/bin/ будет
доступен исполняемый файл rgb-lightning-node. Убедитесь, что
этот путь находится в вашем $PATH, чтобы вы могли вызывать
команду из любой директории.
Требования к производительности
Для работы демона rgb-lightning-node требуется наличие и настройка
:
- Узел
bitcoind**
Каждый экземпляр RLN должен будет взаимодействовать с bitcoind для
трансляции и мониторинга своих транзакций на цепи. Демону необходимо предоставить
аутентификацию (логин/пароль) и URL (хост/порт).
- Индексатор** (Electrum или Esplora)
Демон должен уметь выводить список и изучать транзакции на цепи, в частности, находить UTXO, на котором был привязан актив. Вам нужно будет указать URL вашего сервера Electrum или Esplora.
- Прокси RGB**
Как уже говорилось в предыдущих главах, прокси-сервер - это компонент (необязательный, но настоятельно рекомендуемый), упрощающий обмен согласованиями между пирами Lightning. И снова необходимо указать URL.
Идентификаторы и URL вводятся при разблокировке демона через API. Подробнее об этом позже.
Запуск регтеста
Для простого использования есть скрипт regtest.sh, который
автоматически запускает через Docker набор сервисов: bitcoind, electrs (индексатор), rgb-proxy-server.
Это позволяет запустить локальную, изолированную, предварительно настроенную среду. Она создает и уничтожает контейнеры и каталоги данных при каждой перезагрузке. Мы начнем с запуска файла :
./regtest.sh start
Этот скрипт будет :
- Создайте каталог
docker/для хранения файлов ; - Запустите
bitcoindв regtest, а также индексаторelectrsиrgb-proxy-server; - Подождите, пока все будет готово к использованию.
Далее мы запустим несколько узлов RLN. В отдельных оболочках запустите, например, (для запуска 3 узлов RLN) :
# 1st shell
rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \
--ldk-peer-listening-port 9735 --network regtest
# 2nd shell
rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \
--ldk-peer-listening-port 9736 --network regtest
# 3rd shell
rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \
--ldk-peer-listening-port 9737 --network regtest
- Параметр
--network regtestуказывает на использование конфигурации regtest; --daemon-listening-portуказывает, на каком REST-порту узел Lightning будет прослушивать вызовы API (JSON);--ldk-peer-listening-portуказывает, на каком порту Lightning p2p слушать;dataldk0/,dataldk1/- это пути к каталогам хранения (каждый узел хранит свою информацию отдельно).
Вы также можете выполнять команды на узлах RLN из браузера:
https://rgb-tools.github.io/rgb-lightning-node/
Чтобы узел мог открыть канал, он должен сначала иметь биткоины на адресе, сгенерированном с помощью следующей команды (например, для узла n°1):
curl -X POST http://localhost:3001/address
В ответе вы найдете адрес.
На bitcoind Regtest мы собираемся добыть несколько биткоинов. Выполнить
./regtest.sh mine 101
Отправьте средства на адрес узла, указанный выше:
./regtest.sh sendtoaddress <address> <amount>
Затем заминируйте блок, чтобы подтвердить транзакцию:
./regtest.sh mine 1
Запуск Testnet (без Docker)
Если вы хотите протестировать более реалистичный сценарий, вы можете запустить 3 узла RLN в Testnet, а не в Regtest, указав на публичные сервисы:
rgb-lightning-node dataldk0/ --daemon-listening-port 3001 \
--ldk-peer-listening-port 9735 --network testnet
rgb-lightning-node dataldk1/ --daemon-listening-port 3002 \
--ldk-peer-listening-port 9736 --network testnet
rgb-lightning-node dataldk2/ --daemon-listening-port 3003 \
--ldk-peer-listening-port 9737 --network testnet
По умолчанию, если конфигурация не найдена, демон попытается использовать файл :
bitcoind_rpc_host:electrum.iriswallet.combitcoind_rpc_port:18332- indexer_url
:ssl://electrum.iriswallet.com:50013` proxy_endpoint:rpcs://proxy.iriswallet.com/0.2/json-rpc
С логином :
bitcoind_rpc_username:userbitcoind_rpc_username:password
Вы также можете настроить эти элементы с помощью API init/unlock.
Выпуск токена RGB
Чтобы выпустить токен, мы начнем с создания "цветных" UTXO:
curl -X POST -H "Content-Type: application/json" \
-d '{
"up_to": false,
"num": 4,
"size": 2000000,
"fee_rate": 4.2,
"skip_sync": false
}' \
http://localhost:3001/createutxos
Вы, конечно, можете адаптировать заказ. Чтобы подтвердить сделку, мы моем :
./regtest.sh mine 1
Теперь мы можем создать актив RGB. Команда будет зависеть от типа актива,
который вы хотите создать, и его параметров. Здесь я создаю токен NIA (Non Inflatable Asset) под названием "PBN" с запасом в 1000 единиц. Параметр precision позволяет определить делимость единиц.
curl -X POST -H "Content-Type: application/json" \
-d '{
"amounts": [
1000
],
"ticker": "PBN",
"name": "Plan B Network",
"precision": 0
}' \
http://localhost:3001/issueassetnia
В ответе указывается идентификатор вновь созданного актива. Не забудьте записать этот идентификатор. В моем случае это :
rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10
Затем вы можете передать его в цепь или распределить в канале Lightning. Именно этим мы и займемся в следующем разделе.
Открытие канала и передача актива RGB
Сначала вы должны подключить свой узел к аналогу в сети Lightning с помощью
команды /connectpeer. В моем примере я контролирую оба узла.
Поэтому я получу открытый ключ второго узла Lightning с помощью этой
команды:
curl -X 'GET' \
'http://localhost:3002/nodeinfo' \
-H 'accept: application/json'
Команда возвращает открытый ключ моего узла n°2:
031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94
Далее мы откроем канал, указав соответствующий актив (PBN).
Команда /openchannel позволяет задать размер канала в сатоши и выбрать
включение актива RGB. Это зависит от того, что вы хотите создать, но в моем случае
команда выглядит так: :
curl -X POST -H "Content-Type: application/json" \
-d '{
"peer_pubkey_and_opt_addr": "031e81e4c5c6b6a50cbf5d85b15dad720fec92c62e84bafb34088f0488e00a8e94@localhost:9736",
"capacity_sat": 1000000,
"push_msat": 10000000,
"asset_amount": 500,
"asset_id": "rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10",
"public": true,
"with_anchors": true,
"fee_base_msat": 1000,
"fee_proportional_millionths": 0,
"temporary_channel_id": "a8b60c8ce3067b5fc881d4831323e24751daec3b64353c8df3205ec5d838f1c5"
}' \
http://localhost:3001/openchannel
Узнайте больше здесь:
peer_pubkey_and_opt_addr: Идентификатор пира, к которому мы хотим подключиться (открытый ключ, найденный ранее);capacity_sat: Общая емкость канала в сатоши ;push_msat: Сумма в миллисатоши, первоначально передаваемая пиру при открытии канала (здесь я сразу передаю 10 000 сат, чтобы он мог сделать RGB-передачу позже);asset_amount: Количество RGB-активов, которые будут переданы каналу;asset_id: Уникальный идентификатор актива RGB, задействованного в канале;public: Указывает, должен ли канал быть общедоступным для маршрутизации в сети.
Для подтверждения транзакции добывается 6 блоков:
./regtest.sh mine 6
Канал Lightning теперь открыт и также содержит 500 токенов PBN на стороне узла n°1. Если узел n°2 хочет получить токены PBN,
он должен сгенерировать счет-фактуру. Вот как это сделать:
curl -X POST -H "Content-Type: application/json" \
-d '{
"amt_msat": 3000000,
"expiry_sec": 420,
"asset_id": "rgb:fc7fMj5S-8yz!vIl-260BEhU-Hj1skvM-ZHcjfyz-RTcWc10",
"asset_amount": 100
}' \
http://localhost:3002/lninvoice
С :
amt_msat: Сумма счета в миллисатоши (минимум 3000 сат) ;expiry_sec: время истечения срока действия счета-фактуры в секундах ;asset_id: идентификатор актива RGB, связанного со счетом-фактурой;asset_amount: Сумма актива RGB, который будет передан с этим счетом-фактурой.
В ответ вы получите RGB-фактуру (как описано в предыдущих главах):
lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj
Теперь мы оплатим этот счет с первого узла, на котором хранится необходимая
наличность с токеном PBN:
curl -X POST -H "Content-Type: application/json" \
-d '{
"invoice": "lnbcrt30u1pncgd4rdqud3jxktt5w46x7unfv9kz6mn0v3jsnp4qv0grex9c6m22r9ltkzmzhddwg87eykx96zt47e5pz8sfz8qp28fgpp5jksvqtleryhvwr299qdz96qxzm24augy5agkdhltudk463lt9dassp5d6n0sqgl0c4gx52fdmutrdtqamt0y4xuz2rcgel4hpjwne08gmls9qyysgqcqpcxqzdylz5wfnkywnxvvmkvnt2x4fj6wre0gshvjtv95ervvzzg4592t2gdgchx6mkf5k45jrrdfn8j73d2f2xx4mrxycq7qzry4v4jan6uxhhacyqa4gn6plggwpq9j74tu74f2zsamtz6ymt600p8su4c4ap9g9d8ku2x3wdh6fuc8fd8pff2yzpjrf24ys3cltca9fgqut6gzj"
}' \
http://localhost:3001/sendpayment
Оплата была произведена. Это можно проверить, выполнив команду :
curl -X 'GET' \
'http://localhost:3001/listpayments' \
-H 'accept: application/json'
Вот как развернуть узел Lightning, модифицированный для переноса RGB-активов. Эта демонстрация основана на :
- Среда regtest (через
./regtest.sh) или testnet ; - Узел Lightning (
rgb-lightning-node), основанный наbitcoind, индексаторе иrgb-proxy-server; - Серия JSON REST API для открытия/закрытия каналов, выпуска токенов, передачи активов через Lightning и т. д.
Благодаря этому процессу:
- Транзакции молниеносного взаимодействия включают дополнительный выход (OP_RETURN или Taproot) с привязкой RGB-перехода;
- Переводы осуществляются точно так же, как и традиционные платежи Lightning, но с добавлением токена RGB;
- Несколько узлов RLN могут быть связаны для маршрутизации и экспериментов с платежами между несколькими узлами при условии достаточной ликвидности как биткоинов, так и активов RGB на пути.
Проект по-прежнему находится на стадии альфа-версии. Поэтому настоятельно рекомендуется ограничиться тестовыми средами (regtest, testnet).
Возможности, открываемые этой совместимостью LN-RGB, весьма значительны: стабильные монеты на Lightning, DEX layer-2, перевод взаимозаменяемых токенов или NFT по очень низкой цене... В предыдущих главах были описаны концептуальная архитектура и логика проверки. Теперь у вас есть практическое представление о том, как запустить такой узел в работу, для ваших будущих разработок или тестов.
Заключительный раздел
Отзывы и рейтинги
true
Заключение
true