Данный текст — продолжение серии статей, в которых я рассматриваю структуру (предположительно) готовящейся к выходу в этом году распределенной сети Telegram Open Network (TON). В предыдущей части я описал её самый базовый уровень — способ взаимодействия узлов между собой.
На всякий случай напомню, что к разработке этой сети я отношения не имею и весь материал почёрпнут из открытого (хотя и непроверенного) источника — документа (ещё к нему есть прилагающаяся брошюра, излагающая вкратце основные моменты), появившегося в конце прошлого года. Объем информации в этом документе, на мой взгляд, свидетельствует о его подлинности, хотя никаких официальных подтверждений тому нет.
Сегодня посмотрим на основной компонент TON — блокчейн.
Базовые понятия
Аккаунт (account). Некий набор данных, идентифицируемый 256-битным числом account_id (чаще всего это публичный ключ владельца аккаунта). В базовом случае (см. ниже нулевой воркчейн), под этими данными подразумевается баланс пользователя. «Занять» конкретный account_id может кто угодно, но изменять его значение можно только по определённым правилам.
Смарт-контракт (smart-contract). По сути — частный случай аккаунта, дополненный кодом смарт-контракта и хранилищем его переменных. Если в случае «кошелька» можно зачислять и списывать деньги из него по относительно простым и заранее определённым правилам, то в случае смарт-контракта эти правила записаны в виде его кода (на некоем Тьюринг-полном языке программирования).
Состояние блокчейна (state of blockchain). Совокупность состояний всех аккаунтов/смарт-контрактов (в абстрактном смысле — хэш-таблица, где ключами являются идентификаторы аккаунтов, а значениями — хранимые в аккаунтах данные).
Сообщение (message). Выше я употребил выражение «зачислять и списывать деньги» — это частный пример сообщения («передать N грамм с аккаунта account_1 на аккаунт account_2»). Очевидно, отправить такое сообщение может только узел, владеющий закрытым ключом аккаунта account_1 — и способный подтвердить это подписью. Результатом доставки таких сообщений обычному аккаунту является увеличение его баланса, а смарт-контракту — выполнение его кода (который обработает прием сообщения). Разумеется, возможны и другие сообщения (переносящие не денежные суммы, а произвольные данные между смарт-контрактами).
Транзакция (transaction). Факт доставки сообщения называется транзакцией. Транзакции изменяют состояние блокчейна. Именно из транзакций (записей о доставке сообщений) состоят блоки в блокчейне. В этом плане можно представлять себе состояние блокчейна как инкрементальную базу данных — все блоки являются «диффами», которые нужно применить последовательно, чтобы получить текущее состояние БД. О конкретике упаковки этих «диффов» (и восстановлении полного состояния по ним) пойдёт речь в следующей статье.
Блокчейн в TON: что это и зачем?
Как упоминалось в предыдущей статье, блокчейн — это структура данных, элементы (блоки) которой упорядочены в «цепь», и каждый следующий блок цепи содержит в себе хэш предыдущего. В комментариях задали вопрос: а зачем вообще нужна такая структура данных, когда у нас уже есть DHT — распределённая хэш-таблица? Очевидно, что какие-то данные можно хранить и в DHT, но это подходит только для не слишком «чувствительной» информации. Балансы криптовалюты хранить в DHT нельзя — в первую очередь из-за отсутствия проверок на целостность. Собственно, вся сложность структуры блокчейна вырастает ради предотвращения вмешательств в хранимые в нём данные.
Однако блокчейн в TON выглядит ещё сложнее, чем в большинстве других распределённых систем — и на то есть две причины. Первая — стремление минимизировать потребность в форках. В традиционных криптовалютах все параметры заданы на начальном этапе и любая попытка их изменить приводит фактически к появлению «альтернативной вселенной криптовалюты». Вторая причина — поддержка дробления (шардинга, шардирования) блокчейна. Блокчейн — структура, не способная стать меньше с течением времени; и обычно каждый узел, отвечающий за работоспособность сети, вынужден хранить её полностью. В традиционных (централизованных) системах для решения подобных проблем применяется шардирование: часть записей в БД находится на одном сервере, часть — на другом, и т.д. В случае с криптовалютами такая функциональность пока что довольно редка — в частности, из-за того, что сложно добавить шардирование в систему, где оно не было запланировано изначально.
Каким же образом TON планирует решить обе вышеописанных проблемы?
Содержимое блокчейна. Воркчейны.
В первую очередь, поговорим о том, что же планируется хранить в блокчейне. Храниться там будут состояния аккаунтов («кошельков» в базовом случае) и смарт-контрактов (для простоты будем считать, что это то же, что и аккаунты). По сути, это будет обычная хэш-таблица — ключами в ней будут идентификаторы account_id, а значениями — структуры данных, содержащих в себе такие вещи, как:
- баланс;
- код смарт-контракта (только для смарт-контрактов);
- хранилище данных смарт-контракта (только для смарт-контрактов);
- статистика;
- (опционально) публичный ключ для переводов с аккаунта, по умолчанию account_id;
- очередь исходящих сообщений (сюда они заносятся для пересылки получателю);
- список последних доставленных этому аккаунту сообщений.
Как было сказано выше, непосредственно блоки состоят из транзакций — сообщений, доставленных различным аккаунтам account_id. Однако кроме account_id сообщения содержат также 32-битное поле workchain_id — идентификатор т.н. воркчейна (workchain, working blockchain). Это позволяет иметь несколько независимых друг от друга блокчейнов с разными конфигурациями. При этом workchain_id = 0 считается особым случаем, нулевым воркчейном — именно находящиеся в нём балансы будут соответствовать криптовалюте TON (Grams). Вероятнее всего, на первых порах других воркчейнов существовать не будет вовсе.
Шардчейны. Infinite Sharding Paradigm.
Но на этом рост количества блокчейнов не останавливается. Разберёмся с шардингом. Представим, что каждому аккаунту (account_id) выделен свой собственный блокчейн — в нём лежат все приходящие ему сообщения — и состояния всех таких блокчейнов хранятся на отдельных узлах.
Конечно, это весьма расточительно: скорее всего, в каждый из этих шардчейнов (shardchain, shard blockchain) транзакции будут поступать очень редко, а мощных узлов понадобится много (забегая вперёд, отмечу, что речь идёт не просто о клиентах на мобильных телефонах — а о серьёзных серверах).
Поэтому шардчейны объединяют в себе аккаунты по двоичным префиксам их идентификаторов: если шардчейн имеет префикс 0110, то в него попадут транзакции всех account_id, которые начинаются с этих цифр. Этот shard_prefix может иметь длину от 0 до 60 бит — и главное, что он может меняться динамически.
Как только в один из шардчейнов начинает поступать чрезмерно много транзакций, работающие над ним узлы по заранее определённым правилам «расщепляют» его на два дочерних — их префиксы будут на один бит длиннее (и для одного из них этот бит будет равен 0, а для другого — 1). Например, shard_prefix = 0110b расщепится на 01100b и 01101b. В свою очередь, если два «соседних» шардчейна начнут чувствовать себя достаточно вольготно (в течение некоторого времени), они снова сольются воедино.
Таким образом, шардирование делается «снизу вверх» — мы предполагаем, что каждый аккаунт обладает своим шардом, но они — до поры до времени — «склеены» по префиксам. Это и подразумевает под собой Infinite Sharding Paradigm (парадигма бесконечного шардирования).
Отдельно хочется подчеркнуть, что воркчейны существуют только виртуально — на самом деле, workchain_id это часть идентификатора конкретного шардчейна. Говоря формальным языком, каждый шардчейн определяется парой чисел (workchain_id, shard_prefix).
Исправление ошибок. Вертикальные блокчейны.
Традиционно считается, что любая транзакция в блокчейне является «высеченной в камне». Однако, в случае с TON предусмотрена возможность «переписать историю» — в случае, если некто (т.н. узел-«рыбак») докажет, что один из блоков был подписан некорректно. В этом случае в соответствующий шардчейн добавляется специальный корректирующий блок, содержащий хэш самого исправляемого блока (а не последнего блока в шардчейне). Представляя шардчейн как цепочку блоков, выложенную по горизонтали, можно сказать, что корректирующий блок подцепляется к ошибочному блоку не вправо, а сверху — поэтому считается, что он становится частью маленького «вертикального блокчейна». Таким образом, можно сказать, что шардчейны являются двумерными блокчейнами.
В случае если после ошибочного блока на внесённые им изменения ссылались последующие блоки (т.е., были совершены новые транзакции на основе невалидных), к этим блокам так же «сверху» добавляются корректирующие. Если блоки не затрагивали «поражённую» информацию, на них эти «корректирующие волны» не распространяются. Например, в иллюстрации выше некорректной была признана транзакция первого блока, увеличивающая баланс аккаунта C — поэтому транзакция, уменьшающая баланс этого аккаунта в третьем блоке, также должна быть аннулирована, а поверх самого блока закоммичен корректирующий блок.
Надо заметить — хотя корректирующие блоки и изображаются расположенными «над» оригинальными, фактически они будут дописаны в конец соответствующего блокчейна (туда, где должны находиться хронологически). Двумерное расположение лишь показывает, к какой точке в блокчейне они будут «подцеплены» (посредством находящегося в них хэша оригинального блока).
Можно отдельно пофилософствовать о том, насколько хорошим является решение «менять прошлое». Казалось бы, если мы допускаем возможность появления некорректного блока в шардчейне, то нельзя не допустить и возможности появления ошибочного корректирующего блока. Здесь, насколько я могу судить, разница в количестве узлов, которое должно достигнуть консенсуса по поводу новых блоков — над каждым шардчейном будет трудиться относительно небольшая «рабочая группа» узлов (довольно часто меняющая свой состав), а внесение корректирующих блоков потребует согласия вообще всех узлов-валидаторов. Подробнее о валидаторах, рабочих группах и других ролях узлов я расскажу в следующей статье.
Один блокчейн, чтоб править всеми
Выше перечислено много информации о различных видах блокчейнов, которую саму по себе тоже следует где-то хранить. В частности, речь о следующих сведениях:
- о количестве и конфигурациях воркчейнов;
- о количестве шардчейнов и их префиксах;
- о том, какие узлы в данный момент ответственны за какие шардчейны;
- хэши последних добавленных блоков во все шардчейны.
Как вы уже могли догадаться, все эти вещи записываются в ещё одно хранилище-блокчейн — мастерчейн (masterchain, master blockchain). Благодаря наличию в его блоках хэшей от блоков всех шардчейнов, он делает систему сильно связанной. В том числе это означает, что генерация нового блока в мастерчейне будет происходить непосредственно после генерации блоков в шардчейнах — ожидается, что блоки в шардчейнах будут появляться почти одновременно примерно каждые 5 секунд, а очередной блок в мастерчейне — спустя секунду после этого.
Но кто же будет ответственен за реализацию всей этой титанической работы — за пересылку сообщений, выполнение смарт-контрактов, формирование блоков в шардчейнах и мастерчейне, да ещё и проверку блоков на ошибки? Неужели всё это будут втихомолку делать телефоны миллионов пользователей с установленным на них клиентом Телеграма? Или, быть может, команда Дуровых откажется от идей децентрализации и это будут делать их сервера по-старинке?
На самом деле, ни тот, ни другой ответ не является правильным. Но поля этой статьи стремительно заканчиваются, поэтому разговор о различных ролях узлов (вы могли уже заметить упоминания некоторых из них), а также о механиках их работы пойдёт уже в следующей части.
Комментарии (12)
kondor12
10.05.2018 16:59+1Хмм, непонятен момент с перезаписью истории. То есть подразумевается, что существует вероятность некорректной транзакции, которую нужно будет исправить вертикальными блокчейнами. А если в результате корректировки невалидных блоков у кого-нибудь окажется отрицательный баланс? Не возможность ли это для мошенничества? Например кто-нибудь оплатит что-нибудь с помощью ton-валюты, не имея для этого в действительности средств.
deNULL Автор
10.05.2018 17:10Разница станет понятнее, когда я разберу разделение ответственности между узлами. В каждый момент времени есть группы узлов, которые ответственны за добавление блоков в конкретный шардчейн. В группе таких узлов относительно немного (скажем, от десятков до сотни — в зависимости от того, на сколько шардов поделён блокчейн).
Чтобы появилась некорректная транзакция, нужно, чтобы мошенник смог вмешаться в действия этой рабочей группы. Если он сделает так, что две трети узлов проголосуют за включение в блок некорректной транзакции, она туда попадет.
Только тогда может в этот процесс может включиться (почти) кто угодно — и призвать к созданию корректирующего (вертикального) блока, да. Но, насколько я понимаю, тут уже потребуется одобрение двух третей не от рабочей группы, а от всех узлов-валидаторов, добавляющих новые блоки (их количество будет ближе к тысяче). Поэтому сжульничать на этом этапе становится ещё сложнее.
В конечном итоге ваш вопрос аналогичен вопросу «а что будет, если мошенник сможет провести атаку 51%?». Ну, если в какой-то момент времени мошенник сможет воздействовать на подавляющее число ключевых узлов сети, то понятно, что ничего хорошего из этого не выйдет. Идея в том, чтобы сделать такими узлами не один-два сервера, как в централизованных системах, а чуть побольше.Darth_Malok
11.05.2018 08:50Либо вы не поняли вопрос, либо я понял его по своему.
Ситуация: Благодаря моим действиям я создаётся некорректная транзакция по переводу валюты с моего кошелька на ваш, после чего вы расплачиваетесь всей этой суммой в магазине, покупая новый смартфон. Обе транзакции провела одна и та же рабочая группа.
Вдруг махинация вскрывается, и некорректная транзакция отменяется. Что происходит в этом случае? У вас становится отрицательным баланс? У магазина отнимаются средства на кошельке и он несёт убытки? Если магазин уже перевёл эти деньги поставщику, отнимутся у поставщика?
Всё больше складывается впечатление, что не получится сделать надёжную «полудецентрализованную» систему. Либо единый центр, либо полная децентрализация с майнингом.deNULL Автор
11.05.2018 15:08Отрицательный баланс — это невалидное состояние блокчейна. Никакая транзакция к нему приводить не должна (иначе она тоже невалидна).
Если в результате корректировки какой-то транзакции у получателя станет баланс слишком мал, чтобы прошла следующая транзакция от него — она тоже будет отменена. И так далее, по цепочке.
Если же средств достаточно (у вас, магазина, поставщика), то на этом распространение коррекций оборвется и в соответствующем кошельке просто станет меньше денег.
В общем-то, эти проблемы никак не характерны для полудецентрализованной системы. Со всяким фродом, насколько я понимаю, и централизованным системам приходится бороться примерно такими же способами.
hunroll
11.05.2018 15:08Насколько я понимаю концепцию Proof of Stake, нода, которая «ошиблась» будет отвечать за это как раз из своего Stake. Это было бы правильно.
deNULL Автор
11.05.2018 15:10Это тоже верно, но неизвестно, будет ли размер штрафа связан с конкретными суммами в транзакциях (и непонятно, стоит ли его к ним привязывать).
hunroll
11.05.2018 15:18Ну если можно будет провернуть нелегальную транзакцию на сумму большую, чем сумма штрафа — то сразу же найдутся те, кто этим воспользуется.
Отменять транзакцию тоже не выглядит правильно потому что в случае с магазином — я могу купить товар за «фальшивые» деньги, товар у меня останется, а у продавца уменьшат баланс. Получится всё как с наличкой, но мы ведь хотим от этого уйти?)
Я, конечно, не разработчик блокчейнов, но считаю единственно верным решением штрафовать того, кто подписал невалидную транзакцию, так чтобы продавец действительно получил свои деньги, но уже валидной транзакцией с кошелька ноды.
darkms5
12.05.2018 02:20А можно чуть подробнее про «предусмотрена возможность «переписать историю» — в случае, если некто (т.н. узел-«рыбак») докажет, что один из блоков был подписан некорректно»?
В частности, интересно, кому и как «некто» будет доказывать, что блок подписан некорректно?deNULL Автор
12.05.2018 02:40Все данные, хранимые в блокчейне, будут упорядочены в хитрую структуру — дерево Меркла. Это штука, сама по себе похожая на блокчейн, только он линейные, а эта структура — ветвящаяся. Благодаря ей вводится понятие «доказательств Меркла» (Merkle proofs). Вкратце — если мы знаем хэш корня дерева, то чтобы подтвердить, что какой-то кусочек дерева действительно ему принадлежит, не нужно целиком иметь доступ к дереву — нужны только хэши, ведущие от корня к искомой ветке.
Чтобы определить, допустимо ли было включать какую-то транзакцию в блок, нужно получить состояние шардчейна, из которого она отправлена. Например, если на балансе исходного аккаунта было недостаточно средств — транзакция невалидна, в блок её нельзя было добавлять. Но переслать проверяющим узлам (валидаторам) всё состояние шардчейна тяжело — поэтому как раз полезно прислать только часть шардчейна, соответствующую одному аккаунту, и вместе с ней — доказательство Меркла, которое подтверждает подлинность этой части.
Дальше это заявление обрабатывает текущий набор валидаторов, проверяя корректность доказательства. Если они коллективно согласятся с тем, что транзакция включена в блок неправомерно, то добавят новый корректирующий блок.powerman
12.05.2018 07:54+1Т.е. причины переписывания истории в TON не имеют отношения к причинам, по которым это ранее требовалось в других блокчейнах (украли слишком уж много денег, баг в смартконтракте, etc.)?
aleks_raiden
Спасибо огромное! С нетерпением ожидаю следующей статьи.
Expany
присоединяюсь, очень легко читается и воспринимается.