Последний компонент проекта TON, который мы кратко обсудим в этом тексте, — это TON Payments, платформа для (микро) платежных каналов и передачи значений «сети мгновенных платежей».
Это позволит осуществлять «мгновенные» платежи без необходимости фиксировать все транзакции в блокчейне, оплачивать соответствующие комиссии за транзакции (например, за потребленный газ) и ждать пять секунд, пока блок, содержащий рассматриваемые транзакции, не будет подтвержден.
Общие накладные расходы на такие мгновенные платежи настолько малы, что их можно использовать для микроплатежей. Например, служба хранения файлов TON может взимать с пользователя плату за каждые 128 Кбайт загруженных данных, а платный прокси-сервер TON может потребовать небольшую микроплату за каждые 128 Кбайт ретранслируемого трафика.
Хотя платформа TON Payments, вероятно, будет выпущена позже, чем основные компоненты проекта TON, некоторые соображения необходимо учесть в самом начале. Например, виртуальная машина TON (VM TON), используемая для выполнения кода смарт-контрактов блокчейна TON, должна поддерживать некоторые специальные операции с доказательствами Меркла. Если такая поддержка отсутствует в исходном проекте, добавление ее на более позднем этапе может стать проблематичным. Однако мы увидим, что VM TON изначально поддерживает «умные» каналы оплаты.
Каналы оплаты
Мы начнем с обсуждения каналов оплаты «напрямую» и способов их реализации в блокчейне TON.
Идея платежного канала
Предположим, две стороны (A и B) знают, что в будущем им нужно будет совершать множество платежей друг другу. Вместо того чтобы фиксировать каждый платеж как транзакцию в блокчейне, они создают общий «денежный пул» (или, возможно, небольшой частный банк с ровно двумя счетами) и вносят в него некоторые средства: A вносит a монет, B вносит b монет. Это достигается путем создания специального смарт-контракта в блокчейне и отправкой на него средств.
Перед созданием «денежного пула» стороны соглашаются на определенный протокол. Они будут отслеживать состояние пула, то есть свои балансы в общем пуле. Первоначально состоянием является (a, b), что означает, что монеты на самом деле принадлежат A, а b монет принадлежат B. Затем, если A хочет заплатить d монет в пользу B, они могут просто согласиться с тем, что новое состояние — (a’, b’) = (a — d, b + d). Впоследствии, если, скажем, B хочет заплатить d’ монет в пользу A, состояние станет (a”, b”) = (a’ + d’, b’ — d’) и так далее.
Все это обновление балансов внутри пула происходит полностью вне сети. Когда две стороны решают снять причитающиеся им средства из пула, они делают это в соответствии с окончательным состоянием пула. Это достигается путем отправки специального сообщения в смарт-контракт, содержащего согласованное конечное состояние (a *, b *) вместе с подписями как A, так и B. Затем смарт-контракт отправляет a * монет в A, b * монеты в B и самоуничтожается.
Этот смарт-контракт вместе с сетевым протоколом, используемым A и B для обновления состояния пула, представляет собой простой платежный канал между A и B. Согласно классификации, описанной в 4.1.2, это смешанный сервис: часть его состояние находится в блокчейне (смарт-контракте), но большая часть соответствующих обновлений состояния выполняется вне сети (по сетевому протоколу). Если все идет хорошо, две стороны смогут выполнить столько платежей друг другу, сколько захотят (с единственным ограничением, что не должна быть превышена «пропускная способность» канала, т. е. их остатки на платежном канале не будут отрицательными), совершая только две транзакции в блокчейне: одна для открытия (создания) платежного канала (смарт-контракт), а другая для его закрытия (уничтожения).
Не требующие доверия каналы оплаты
Предыдущий пример был несколько нереалистичным, так как он предполагает, что обе стороны готовы сотрудничать и никогда не обманывают друг друга, чтобы получить какое-либо преимущество. Представьте, например, что A решит не подписывать окончательный баланс (a’, b’) с a’ <a. Такой вариант может поставить B в затруднительное положение.
Чтобы защитить пользователей от таких сценариев, обычно разрабатываются «не требующие доверия» протоколы каналов оплаты, которые не требуют от сторон доверия друг к другу, и предусматривают наказание любой стороны, которая попытается обмануть другую сторону.
Обычно это достигается с помощью подписей. Смарт-контракт платежного канала знает открытые ключи A и B и при необходимости может проверять их подписи. Протокол платежного канала требует, чтобы стороны подписали промежуточные состояния и отправили подписи друг другу. Затем, если одна из сторон обманывает — например, делает вид, что какое-то состояние платежного канала никогда не существовало, — ее некорректное поведение можно доказать, поставив свою подпись на этом состоянии. Смарт-контракт платежного канала выступает в роли «сетевого арбитра», способного обрабатывать жалобы двух сторон друг на друга и наказывать виновную сторону, конфисковав все ее средства и передав их другой стороне.
Простой двунаправленный синхронный канал оплаты, не требующий доверия
Рассмотрим следующий, более реалистичный пример: Пусть состояние платежного канала описывается тройкой (бi, i, оi, где i — порядковый номер состояния (изначально он равен нулю, а затем увеличивается на единицу при последующем появляется состояние), бi — дисбаланс канала (это означает, что A и B владеют монетами a + бi и b — бi соответственно), а oi — сторона, которой разрешено генерировать следующее состояние (либо A, либо B). Каждое состояние должно быть подписано как А, так и B, прежде чем будет достигнут какой-либо дальнейший прогресс.
Теперь, если A хочет передать d монет B внутри платежного канала, а текущее состояние — Si = (бi, i, oi) с oi = A, то он просто создает новое состояние Si + 1 = (бi — d , i + 1, oi + 1), подписывает его и отправляет B вместе со своей подписью. Затем B подтверждает это, подписывая и отправляя копию своей подписи A. После этого обе стороны получают копию нового состояния с обеими своими подписями, и может произойти новая передача.
Если A хочет передать монеты B в состоянии Si с oi = B, то сначала он просит B зафиксировать последующее состояние Si+1 с таким же дисбалансом бi+1 = бi, но с oi+1 = A После этого, A сможет Выполнить передачу.
Когда две стороны соглашаются закрыть платежный канал, они ставят свои специальные окончательные подписи на состояние Sk, которое они считают окончательным, и вызывают чистый или двусторонний метод финализации смарт-контракта платежного канала, отправив ему окончательное состояние вместе с обеими окончательными подписями.
Если другая сторона не соглашается предоставить свою окончательную подпись или просто перестает отвечать, есть возможность закрыть канал в одностороннем порядке. Для этого сторона, желающая сделать это, вызывает метод односторонней финализации, отправив смарт-контракту свою версию конечного состояния, свою окончательную подпись и самое последнее состояние, имеющее подпись другой стороны. После этого смарт-контракт не сразу воздействует на полученное конечное состояние. Вместо этого он ждет в течение определенного периода времени (например, одного дня), пока другая сторона не представит свою версию окончательного состояния. Когда другая сторона отправляет свою версию, и она оказывается совместимой с уже представленной версией, «истинное» конечное состояние вычисляется смарт-контрактом и используется для соответствующего распределения средств. Если другая сторона не может представить свою версию конечного состояния смарт-контракту, то деньги перераспределяются в соответствии с единственной представленной копией конечного состояния.
Если одна из двух сторон обманывает — например, подписывая два разных состояния как окончательные, подписывая два разных следующих состояния Si+1 и S’i+1, либо подписывая недопустимое новое состояние Si+1 (например, с дисбалансом бi+1 < -a или b) — тогда другая сторона может предоставить доказательство этого неправомерного поведения третьему методу смарт-контракта. Виновная сторона немедленно наказывается полной потерей своей доли в платежном канале.
Этот простой протокол платежного канала справедлив в том смысле, что любая сторона всегда может получить должное, при сотрудничестве или без сотрудничества с другой стороной, и, вероятно, потеряет все свои средства, переданные в платежный канал, если попытается обмануть.
Синхронный платежный канал как простой виртуальный блокчейн с двумя валидаторами
Приведенный выше пример простого синхронного платежного канала можно изменить следующим образом. Представьте, что последовательность состояний S0, S1,…,Sn на самом деле является последовательностью блоков очень простого блокчейна. Каждый блок этого блокчейна содержит по существу только текущее состояние блокчейна и, возможно, ссылку на предыдущий блок (то есть его хэш). Обе стороны A и B выступают в роли валидаторов для этого блокчейна, поэтому каждый блок должен собирать обе подписи. Состояние Si блокчейна определяет назначенного производителя c ^ для следующего блока, поэтому между A и B нет гонки за создание следующего блока. Производителю A разрешено создавать блоки, которые переводят средства от A к B (т. е. уменьшают дисбаланс: бi+1 ≤ бi), а B может переводить средства только от B к A (т. е. увеличивать б).
Если два валидатора согласовывают окончательный блок (и окончательное состояние) блокчейна, он завершается сбором специальных «окончательных» подписей двух сторон и отправкой их вместе с последним блоком в смарт-контракт канала для обработки и соответствующее перераспределение средств.
Если валидатор подписывает недействительный блок, создает форк или подписывает два разных финальных блока, он может быть наказан. При этом доказательство некорректного поведения валидатора предоставляется смарт-контракту, который действует как «ончейн-арбитр» для двух валидаторов; тогда нарушившая сторона теряет все свои деньги, хранящиеся в платежном канале, что аналогично тому, как валидатор теряет свою долю.
Асинхронный платежный канал как виртуальный блокчейн с двумя воркчейнами
Синхронный платежный канал, описанный, имеет определенный недостаток: нельзя начать следующую транзакцию (перевод денег средств внутри платежного канала) до того, как предыдущая будет подтверждена другой стороной. Это можно исправить, заменив единый виртуальный блокчейн, системой из двух взаимодействующих виртуальных воркчейнов (или, скорее, шардчейнов).
Первый из этих воркчейнов содержит только транзакции A, а его блоки могут быть сгенерированы только A. Его состояния: Si = (i, фi, j, ψj), где i — порядковый номер блока (т. е. количество транзакций или денежных переводов, выполненных A на данный момент), фі — это общая сумма, переведенная от A к B на данный момент , j — порядковый номер самого последнего действительного блока в блокчейне B’s котором известно A, ψj — сумма денег, переданная от B к A в его j транзакциях.
Подпись B, помещенная в его j-й блок, также должна быть частью этого состояния. Также могут быть включены хэши предыдущего блока этой воркчейна и j-го блока другой воркчейна. Условия применимости для Si включают фі ≥ 0 фі ≥ фі-1, если i > 0, ψj ≥ 0, и -a ≤ ψj — фi ≤ b. Точно так же второй воркчейн содержит только транзакции B, а его блоки генерируются только B. Его состояния: Tj = (j, ψj , i, φi) с аналогичными условиями выполнения.
Если A хочет перевести средства B, он просто создает новый блок в своем воркчейне, подписывает его и отправляет B, не дожидаясь подтверждения.
Платежный канал завершается подписанием A (его версией) конечного состояния своего блокчейна (со специальной «окончательной подписью»), подписанием B конечного состояния своего блокчейна и представлением этих двух конечных состояний методу чистой финализации смарт-контракта платежного канала. Одностороннее завершение также возможно, однако в этом случае смарт-контракт должен будет дождаться, пока другая сторона представит свою версию окончательного состояния, по крайней мере, в течение некоторого периода отсрочки.
Однонаправленные платежные каналы
Если только A необходимо произвести платежи для B (например, B является поставщиком услуг, а A — его клиентом), то может быть создан канал односторонних платежей. По сути, это просто первый воркчейн, без второго воркчейна. И наоборот, можно сказать, что асинхронный платежный канал, состоит из двух однонаправленных платежных каналов или «полуканалов», управляемых одним и тем же смарт-контрактом.
Более сложные каналы оплаты. «Обещания»
Позже мы увидим, что «сеть мгновенных платежей» , которая обеспечивает мгновенные денежные переводы через цепочки из нескольких платежных каналов, требует более высокой степени сложности задействованных платежных каналов.
В частности, мы хотим иметь возможность давать «обещания» или совершать «условные денежные переводы»: A соглашается отправить c монет B, но B получит деньги только при выполнении определенного условия, например, если B может представить некоторую строку u с HASH(U) = v для известного значения v. В противном случае A может вернуть деньги через определенный период времени.
Такое обещание может быть легко реализовано в сети с помощью простого смарт-контракта. Однако мы хотим, чтобы обещания и другие виды условных денежных переводов были возможны оффчейн, в платежном канале, потому что они значительно упрощают денежные переводы по цепочке платежных каналов, существующих в «сети мгновенных платежей».
Схема «платежный канал как простой блокчейн», здесь становится очень удобной. Рассмотрим более сложный виртуальный блокчейн, состояние которого содержит набор таких невыполненных «обещаний» и количество средств, заблокированных в таких обещаниях. Этот блокчейн — или два воркчейна в асинхронном случае — должны будут явно ссылаться на предыдущие блоки по их хэшам. Тем не менее, общий механизм остается прежним.
Проблемы при использовании сложных смарт-контрактов платежных каналов
Обратите внимание, что, хотя конечное состояние сложного платежного канала все еще невелико, а «чистое» завершение является простым (если две стороны согласовали свои причитающиеся суммы, и обе подписали соглашение, больше ничего не нужно делать), метод одностороннего завершения и метод наказания мошенничества должны быть более сложными. Действительно, они должны иметь возможность принимать доказательства Меркла при неправомерном поведении и проверять, правильно ли были обработаны более сложные транзакции блокчейна платежного канала.
Другими словами, смарт-контракт платежного канала должен иметь возможность работать с доказательствами Меркла, проверять их «хеш-валидность» и должен содержать реализацию функций ev_trans и ev_block для платежного канала (виртуального) блокчейна.
VM TON поддерживает «умные» каналы оплаты
Виртуальная машина TON, используемая для запуска кода смарт-контрактов блокчейна TON, справляется с задачей выполнения смарт-контрактов, необходимых для «умных» или сложных каналов оплаты. На этом этапе парадигма «все есть мешок ячеек» становится чрезвычайно удобной. Поскольку все блоки (включая блоки блокчейна канала мгновенного платежа) представлены как мешки ячеек (и описываются некоторыми алгебраическими типами данных), и то же самое верно для сообщений и доказательств Меркла, доказательство Меркла может быть легко встроено во входящее сообщение, отправленное на смарт-контракт платежного канала.
«Условие хеширования» доказательства Меркла будет проверяться автоматически, и когда смарт-контракт получит доступ к предоставленному «доказательству Меркла», он будет работать с ним, как если бы это было значение соответствующего алгебраического типа данных — хотя и неполное, в котором некоторые поддеревья дерева заменены специальными узлами, содержащими хэш Меркла пропущенного поддерева. Затем смарт-контракт будет работать с этим значением, которое может предоставлять, например, блок (виртуального) блокчейна платежного канала вместе с его состоянием, и будет оценивать функцию ev_block этого блокчейна в этом блоке и предыдущем состоянии. Затем либо вычисление завершается, и конечное состояние может быть сравнено с тем, что заявлено в блоке, либо при попытке доступа к отсутствующему поддереву выдается исключение «отсутствующий узел», указывающее, что доказательство Меркла недействительно.
Таким образом, реализация кода проверки для блокчейнов «умных» платежных каналов оказывается довольно простой при использовании смарт-контрактов блокчейна TON. Можно сказать, что виртуальная машина TON имеет встроенную поддержку для проверки валидности других простых блокчейнов. Единственным ограничивающим фактором является размер доказательства Меркла, которое должно быть включено во входящее сообщение для смарт-контракта (т. е. в транзакцию).
Простой платежный канал в «умном» платежном канале
Мы хотели бы обсудить возможность создания простого (синхронного или асинхронного) платежного канала внутри существующего платежного канала.
Хотя это может показаться несколько запутанным, эту схему не намного сложнее понять и реализовать, чем «обещания». По сути, вместо обещания заплатить c монет другой стороне, если присутствует некоторое решение задачи с хешем, A обещает выплатить B до c монет в соответствии с окончательным расчетом некоторого другого (виртуального) блокчейна платежного канала. Вообще говоря, этот блокчейн другого платежного канала даже не обязательно должен находиться между A и B; в нем могут быть задействованы другие стороны, например C и D, желающие внести монеты c и d в свой простой платежный канал.
Если охватывающий платежный канал асимметричен, два обещания должны быть зафиксированы в двух воркчейнах: A обещает выплатить -б монет B, если окончательный расчет «внутреннего» простого платежного канала дает отрицательный окончательный дисбаланс 6 с 0 ≤ -б ≤ c; и B должен будет пообещать заплатить б в пользу A, если б положителен. С другой стороны, если охватывающий платежный канал является симметричным, это может быть выполнено путем фиксации одной транзакции «создания простого платежного канала» с параметрами (c, d) в блокчейне одного платежного канала с помощью A (который заморозит c монет, принадлежащих A), а затем фиксации специальной «транзакции подтверждения» от B (которая заморозит d монет B).
Мы ожидаем, что внутренний платежный канал будет чрезвычайно простым (например, простой синхронный платежный канал, описанный в 5.1.3), что позволит минимизировать объем предоставляемых доказательств Меркла. Внешний платежный канал должен быть «умным» в смысле.
Сеть платежных каналов или «сеть мгновенных платежей» (Lightning)
Теперь мы можем обсудить «сеть мгновенных платежей» системы TON Payments, которая обеспечивает мгновенные денежные переводы между любыми двумя участвующими узлами.
Ограничения платежных каналов
Платежный канал полезен для сторон, которые собираются выполнять большое количество денежных переводов между своими учетными записями. Однако если нужно перевести средства только один или два раза конкретному получателю, создание платежного канала с ним будет нецелесообразно. Среди прочего, это повлечет за собой замораживание значительной суммы денег в платежном канале и в любом случае потребует как минимум двух транзакций блокчейна.
Сети платежных каналов или «сети мгновенных платежей»
Сети платежных каналов преодолевают ограничения платежных каналов, обеспечивая денежные переводы по цепочкам платежных каналов. Если A хочет перевести деньги в E, ему не нужно устанавливать платежный канал с E. Достаточно иметь цепочку платежных каналов, связывающую A с E через несколько промежуточных узлов — скажем, четыре платежных канала: от A до B, от B до C, от C до D и от D до E.
Обзор сетей платежных каналов
Напомним, что сеть платежных каналов, известная также как «сеть мгновенных платежей», состоит из набора участвующих узлов, некоторые из которых установили между собой долговременные платежные каналы. Мы скоро увидим, что эти платежные каналы должны быть «умными». Когда участвующий узел A хочет перевести деньги любому другому участвующему узлу E, он пытается найти путь, связывающий A с E внутри сети платежных каналов. Когда такой путь находится, выполняется «цепной перевод денег» по этому пути.
Цепные денежные переводы
Предположим, что существует цепочка платежных каналов от А до В, от В до C к D и от D к E. Предположим также, что A хочет передать x монет E.
Упрощенный подход состоял бы в том, чтобы передать x монет В по существующему платежному каналу и попросить его переслать деньги дальше С. Однако не очевидно, почему В просто не возьмет деньги себе. Следовательно, необходимо использовать более изощренный подход, не требующий от всех вовлеченных сторон доверять друг другу.
Этого можно добиться следующим образом. A генерирует большое случайное число u и вычисляет его хэш v = HASH(u). Затем он создает обещание выплатить x монет В, если в его платежном канале с В присутствует число u с хешем v. Это обещание содержит v, но не u, а значение пока держится в секрете.
После этого B создает аналогичное обещание для C в своем платежном канале. Он не боится давать такое обещание, потому что знает о существовании подобного обещания, данного ему А. Если C когда-либо предоставит решение хеш-задачи по сбору x монет, обещанное В, то В немедленно представит это решение задачи A для сбора x монет у A.
Затем создаются аналогичные обещания от C к D и от D к E. Когда все обещания будут выполнены, A запускает передачу, сообщая решение u всем вовлеченным сторонам или только E.
Некоторые мелкие детали опущены в этом описании. Например, эти обещания должны иметь разное время истечения, а обещанная сумма может немного отличаться по цепочке (В может обещать C только x — e монет, где e — небольшая заранее согласованная плата за транзит). Мы пока игнорируем такие детали, потому что они не слишком актуальны для понимания того, как работают платежные каналы и как их можно реализовать в TON.
Виртуальные платежные каналы внутри цепочки платежных каналов
Теперь предположим, что A и E рассчитывают выполнять большое количество платежей друг другу. Они могут создать новый платежный канал между собой в блокчейне, но это все равно будет довольно дорого, потому что некоторые средства будут заблокированы в этом платежном канале. Другой вариант — использовать цепные денежные переводы, для каждого платежа. Однако это потребует большой сетевой активности и большого количества транзакций в виртуальных блокчейнах всех задействованных платежных каналов.
Альтернативой является создание виртуального платежного канала внутри блокчейна, связывающего A и E в сети платежных каналов. Для этого A и E создают (виртуальный) блокчейн для своих платежей, как если бы они собирались создать платежный канал в блокчейне. Однако вместо создания смарт-контракта платежного канала в блокчейне они просят все промежуточные платежные каналы — те, которые связывают A с B, B с C и т. д. — создать внутри них простые платежные каналы, привязанные к виртуальному блокчейну, созданному A и E. Другими словами, теперь обещание перевести деньги в соответствии с окончательным расчетом между A и E существует внутри каждого промежуточного платежного канала.
Если виртуальный платежный канал является однонаправленным, такие обещания могут быть реализованы довольно легко, потому что окончательный дисбаланс 5 будет неположительным, поэтому простые платежные каналы могут быть созданы внутри промежуточных платежных каналов в том же порядке. Таким же образом можно установить срок их действия.
Если виртуальный платежный канал является двунаправленным, ситуация становится несколько сложнее. В этом случае следует разделить обещание передать б монет в соответствии с окончательным расчетом на два «полуобещания»: передать б
- = max (0, -б) монет в прямом направлении и допередать б
- = max (0, б) в обратном направлении. Эти полуобещания могут быть созданы в промежуточных платежных каналах независимо, одна цепочка полуобещаний в направлении от A к E, а другая цепочка — в противоположном направлении.
Поиск путей в сети мгновенных платежей
Пока не обсуждается один вопрос: как A и E найдут путь, соединяющий их в платежной сети? Если платежная сеть не слишком большая, можно использовать протокол типа OSPF: все узлы платежной сети создают оверлейную сеть, а затем каждый узел передает всю доступную информацию (т. е. участвующие платежные каналы) своим соседям по протоколу сплетен. В итоге все узлы будут иметь полный список всех платежных каналов, участвующих в платежной сети, и смогут сами найти кратчайшие пути, например, применив версию алгоритма Дейкстры, измененную с учетом «возможностей» задействованных платежных каналов (т. е. максимальные суммы, которые могут быть переведены по ним). После того, как путь-кандидат будет найден, его можно исследовать с помощью специальной датаграммы ADNL, содержащей полный путь и запрашивающей у каждого промежуточного узла подтверждение существования рассматриваемого платежного канала, и пересылать эту датаграмму дальше в соответствии с путем. После этого можно построить цепочку и запустить протокол для цепных переводов или для создания виртуального платежного канала внутри цепочки платежных каналов.
Оптимизация
Здесь можно сделать некоторые оптимизации. Например, только транзитные узлы сети мгновенных платежей должны участвовать в протоколе типа OSPF. Два «листовых» узла, желающие подключиться через сеть мгновенных платежей, будут передавать друг другу списки транзитных узлов, к которым они подключены (т. е. с которыми они установили платежные каналы, участвующие в платежной сети). Затем можно проверить пути, соединяющие транзитные узлы из одного списка с транзитными узлами из другого списка.