Для любого блокчейн-проекта необходимы не только спецификации формата блока и правил проверки блокчейна, но и сетевого протокола, используемого для распространения новых блоков, отправки и сбора транзакций-кандидатов и т. д. Другими словами, в каждом проекте блокчейн должна быть создана специализированная одноранговая сеть. Эта сеть должна быть одноранговой, поскольку обычно предполагается, что блокчейн-проекты будут децентрализованными, поэтому нельзя полагаться на централизованную группу серверов и использовать традиционную архитектуру «клиент-сервер», как, например, в классических приложениях для онлайн-банкинга.
Даже тонкие клиенты (например, приложения для смартфонов с кошельком для криптовалюты), которые должны подключаться к полным нодам по типу «клиент-сервер», на самом деле могут свободно подключаться к другой полной ноде, если соответствующая предыдущая одноранговая нода выходит из строя, при условии, что протокол, используемый для подключения для полных нод в достаточной степени стандартизирован.
В то время как сетевые потребности синглчейн-проектов, таких как Биткоин или Эфириум, могут быть удовлетворены довольно легко (по сути, необходимо построить «случайную» одноранговую оверлейную сеть и распространять все новые блоки и транзакции-кандидаты с помощью протокола сплетен), мультичейн-проекты с несколькими блокчейнами, такие как TON Blockchain, гораздо более требовательны (например, нужно иметь возможность подписаться на обновления только некоторых шардчейнов, не обязательно всех из них).
Поэтому сетевая часть блокчейна TON и проекта TON в целом заслуживает хотя бы краткого обсуждения.
С другой стороны, как только будут созданы более сложные сетевые протоколы, необходимые для поддержки блокчейна TON, их можно будет легко использовать для целей, не обязательно связанных с непосредственными потребностями блокчейна TON, что позволит обеспечить больше возможностей и гибкость для создания новых сервисов в экосистеме TON.
Краеугольным камнем в построении сетевых протоколов TON является абстрактный сетевой уровень (датаграммы) (TON). Он позволяет всем узлам принимать определенные «сетевые идентификаторы», представленные 256-битными «абстрактными сетевыми адресами», и обмениваться данными (отправлять датаграммы друг другу в качестве первого шага), используя только эти 256-битные сетевые адреса для идентификации отправителя и получателя. В частности, не нужно беспокоиться об адресах IPv4 или IPv6, номерах портов UDP и т.п. — они скрыты в абстрактном сетевым уровне.
Абстрактный сетевой адрес, или просто адрес для краткости, является 256-битным целым числом равным 256-битному публичному ключу ECC. Этот публичный ключ может быть сгенерирован произвольно, таким образом создавая столько сетевых идентификаторов, сколько нравится узлу. Однако для получения (и расшифровки) сообщений, предназначенных для такого адреса, необходимо знать соответствующий закрытый ключ. Фактически, адрес не является открытым ключом; вместо этого это 256-битный хэш (Hash = sha256) сериализированного TL-объекта, который может описывать несколько типов открытых ключей и адресов в зависимости от его конструктора (первые четыре байта). В простейшем случае этот сериализированный TL-объект состоит из 4-байтового магического числа и 256-битного открытого ключа криптографии с эллиптической кривой (ECC); в этом случае адрес будет равен хешу этой 36-байтовой структуры. Однако можно вместо этого использовать 2048-битные ключи RSA или любую другую схему криптографии с открытыми ключами. Когда узел узнает абстрактный адрес другого узла, он также должен получить свой «образ» (т.е. сериализированный TL-объект, хэш которого равен этому абстрактному адресу), иначе он не сможет шифровать и отправлять датаграммы на этот адрес.
Сети более низкого уровня. Реализация UDP. С точки зрения почти всех сетевых компонентов TON, единственное, что существует, — это сеть (сетевой уровень абстрактных датаграмм), способная отправлять датаграммы с одного абстрактного адреса на другой. В принципе, абстрактный сетевой уровень датаграм (ADNL) может быть реализован в различных существующих сетевых технологиях. Однако мы собираемся реализовать его по протоколу UDP в сетях IPv4 / IPv6 (таких как Интернет или интрасети), с необязательным запасным вариантом TCP, если UDP недоступен.
Простейший случай отправки датаграмм с абстрактного адреса отправителя на любой другой абстрактный адрес (с известным изображением) может быть реализован следующим образом. Предположим, что отправитель каким-то образом знает IP-адрес и UDP-порт получателя, которому принадлежит абстрактный адрес назначения, и что и получатель, и отправитель используют абстрактные адреса, полученные из 256-битных открытых ключей ECC.
В этом случае отправитель просто добавляет датаграмм для отправки своей подписью ECC (выполненной с помощью своего закрытого ключа) и адресом своего источника. Результат шифруется открытым ключом получателя, встраивается в датаграмму UDP и отправляется на известный IP-адрес и порт получателя. Поскольку первые 256 бит датаграммы UDP содержат абстрактный адрес получателя, получатель может определить, какой закрытый ключ следует использовать для расшифровки оставшейся части датаграммы. Только после этого раскрывается личность отправителя.
Иногда недостаточно безопасной схемы, когда адреса получателя и отправителя хранятся в незашифрованном виде в дейтаграмме UDP; закрытый ключ отправителя и открытый ключ получателя объединяются вместе с помощью ECDH (эллиптическая кривая Диффи-Хеллмана) для генерации 256-битного общего секрета, который используется впоследствии, наряду со случайным 256-битным одноразовым номером, также включенным в незашифрованную часть, получить ключи AES, используемые для шифрования. Целостность может быть обеспечена, например, путем объединения хеша исходных данных открытого текста в открытый текст перед шифрованием. Преимущество этого подхода состоит в том, что если ожидается обмен более чем двумя дейтаграммами между двумя адресами, общий секрет может быть вычислен только один раз, а затем кэширован, тогда более медленные операции эллиптической кривой больше не будут требоваться для шифрования или дешифрования следующих датаграмм.
В простейшем случае первые 256 бит датаграммы UDP, несущей встроенную дейтаграмму TON ADNL, будут равны адресу получателя. Однако в целом они составляют идентификатор канала. Существуют разные типы каналов. Некоторые из них являются двухточечными; они создаются двумя сторонами, которые желают обмениваться большим количеством данных в будущем и генерировать общий секрет путем обмена несколькими пакетами, путем запуска классической или эллиптической кривой Диффи-Хеллмана (если необходима дополнительная безопасность), или просто одна сторона генерирует случайный общий секрет и отправляет его другой стороне. После этого идентификатор канала извлекается из общего секрета в сочетании с некоторыми дополнительными данными (такими как адреса отправителя и получателя), например, путем хеширования, и этот идентификатор используется в качестве первых 256 битов датаграмм UDP, переносящих данные, зашифрованные с помощью помощь этого общего секрета.
В общем, «канал» или «идентификатор канала» просто выбирает способ обработки входящей датаграммы UDP, известный получателю. Если канал является абстрактным адресом получателя, обработка выполняется; если канал является установленным двухточечным каналом, обработка состоит в расшифровке датаграммы с помощью общего секрета, как описано в /цитата/ и т. д.
В частности, идентификатор канала может фактически выбрать «туннель», когда непосредственный получатель просто пересылает полученное сообщение кому-то другому — фактическому получателю или другому прокси. Некоторые этапы шифрования или дешифрования (напоминающие «луковую маршрутизацию» или даже «чесночную маршрутизацию») могут выполняться по пути, и другой идентификатор канала может быть использован для перешифрованных переадресованных пакетов (например, одноранговая маршрутизация). Равноправный канал может использоваться для пересылки пакета следующему получателю на пути.
Таким образом, некоторая поддержка «туннелирования» и «прокси» — что-то вроде того, что обеспечивается проектами TOR или I2P — может быть добавлена на уровне сетевого уровня абстрактных дейтаграмм TON, не затрагивая функциональность всех высших сетевые протоколы уровня TON, которые были бы независимы от такого дополнения. Эта возможность используется службой TON Proxy.
Обычно TON ADNL будет иметь некоторую «таблицу соседних узлов», содержащую информацию о других известных узлах, таких как их абстрактные адреса и их прообразы (то есть открытые ключи), а также их IP-адреса и порты UDP. Затем он будет постепенно расширять эту таблицу, используя информацию, полученную из этих известных узлов, в качестве ответов на специальные запросы, а иногда и удалять устаревшие записи.
Однако когда узел TON ADNL только запускается, может случиться так, что он не знает ни одного другого узла и может узнать только IP-адрес и UDP-порт узла, но не его абстрактный адрес. Это происходит, например, если легкий клиент не может получить доступ ни к одному из ранее кэшированных узлов и к любым узлам, жестко закодированным в программное обеспечение, и должен попросить пользователя ввести IP-адрес или DNS-домен узла, который необходимо разрешить через DNS.
рассматриваемого узла. Это не требует знания открытого ключа получателя (но сообщение все равно должно содержать личность и подпись отправителя), поэтому сообщение передается без шифрования. Обычно его следует использовать только для получения идентификатора (возможно, единовременного идентификатора, созданного специально для этой цели) получателя и затем для начала более безопасной связи.
Как только становится известен хотя бы один узел, можно легко заполнить «таблицу соседних узлов» и «таблицу маршрутизации» большим количеством записей, изучая их на основе ответов на специальные запросы, отправленные на уже известные узлы. Не все узлы требуются для обработки дейтаграмм, отправленных на нулевой канал, но те, которые используются для начальной загрузки легких клиентов, должны поддерживать эту функцию.
TCP-подобный стриминговый протокол поверх ADNL. ADNL, являющийся малым протоколом датаграмм на основе 256-битных абстрактных адресов может использоваться в качестве основы для более сложных сетевых протоколов. Можно создать, например, TCP-подобный потоковый протокол, используя ADNL в качестве абстрактной замены IP. Однако большинству компонентов проекта TON такой потоковый протокол не нужен.
Надежный протокол датаграмм произвольного размера, построенный на ADNL, называемый RLDP, используется вместо протокола, подобного TCP. Этот надежный протокол датаграмм может использоваться, например, для отправки запросов RPC удаленным хостам и получения от них ответов.
Распределенная хеш-таблица TON (DHT) играет решающую роль в сетевой части проекта TON и используется для определения местоположения других узлов в сети. https://geti2p.net/en/docs/how/garlic-routing
Например, клиент, желающий зафиксировать транзакцию в шардчейне, может захотеть найти валидатора или коллатора этого шардчейна или хотя бы какой-нибудь узел, который мог бы передать транзакцию клиента коллатору. Это можно сделать, посмотрев специальный ключ в TON DHT. Еще одно важное применение TON DHT состоит в том, что его можно использовать для быстрого заполнения таблицы соседних элементов нового узла просто путем поиска случайного ключа или адреса нового узла. Если узел использует проксирование и туннелирование для своих входящих датаграмм, он публикует идентификатор туннеля и его точку входа (например, IP-адрес и порт UDP) в TON DHT; тогда все узлы, желающие отправить датаграммы на этот узел, сначала получат эту контактную информацию от DHT.
TON DHT является членом семейства распределенных хеш-таблиц, подобных Kademlia.
Ключи TON DHT — это просто 256-битные целые числа. В большинстве случаев они вычисляются как SHA256 TL-сериализированного объекта, называемого прообразом ключа или описанием ключа. В некоторых случаях абстрактные адреса узлов сети TON также могут использоваться в качестве ключей TON DHT, потому что они также являются 256-битными, и они также являются хэшами TL-сериализированных объектов. Например, если узел не боится публиковать свой IP-адрес, его может найти любой, кто знает его абстрактный адрес, просто просмотрев этот адрес в виде ключа в DHT.
Значения, присвоенные этим 256-битным ключам, по сути, представляют собой произвольные байтовые строки ограниченной длины. Интерпретация таких байтовых строк определяется прообразом соответствующего ключа; обычно это известно как узлу, который ищет ключ, так и узлу, который хранит ключ.
Полупостоянные сетевые идентификаторы. Сопоставление ключа и значения TON DHT хранится на узлах DHT, по сути, всех участников сети TON. С этой целью любой узел Сеть TON (возможно, за исключением некоторых очень легких узлов), помимо любого количества эфемерных и постоянных абстрактных адресов, имеет как минимум один полупостоянный адрес, который идентифицирует ее как члена TON DHT. Этот полупостоянный или DHT-адрес не их следует менять слишком часто, иначе другие узлы не смогли бы найти ключи, которые они ищут. Если узел не хочет раскрывать свою истинную личность, он генерирует отдельный абстрактный адрес, который будет использоваться только с целью участия в DHT. Однако этот абстрактный адрес должен быть общедоступным, поскольку он будет связан с IP-адресом и портом узла.
Теперь у нас есть как 256-битные ключи, так и 256-битные (полупостоянные) адреса узлов. Мы вводим так называемое расстояние XOR или расстояние Kademlia dK на наборе 256-битных последовательностей, заданное формулой которое интерпретируется как 256-битное целое число без знака.
Здесь обозначает побитовое исключающее ИЛИ (XOR) двух битовых последовательностей одинаковой длины.
Расстояние Kademlia представляет собой метрику набора 2256 всех 256-битных последовательностей. В частности, dK (x, y) = 0 тогда и только тогда, когда x = y, dK(x, y) = dK (y, x) и dK (x, z) ≤ dK (x, y) + dK (y, z). Другое важное свойство состоит в том, что на любом заданном расстоянии от x есть только одна точка: dK (x, y) = dK (x, y’) подразумевает y = y’.
Мы говорим, что распределенная хеш-таблица (DHT) с 256-битными ключами и 256-битными адресами узлов является распределенной хеш-таблицей, подобной Kademlia, если ожидается, что она сохранит значение ключа K на s Kademlia — ближайших к K узлах (т. е. s узлов с наименьшим расстоянием Kademlia от их адресов до K).
Здесь s — небольшой параметр, скажем s = 7, необходимый для повышения надежности DHT (если мы будем хранить ключ только на одном узле, ближайшем к K, значение этого ключа будет потеряно, если этот единственный узел переходит в автономный режим).
Согласно этому определению, TON DHT — это таблица DHT, подобная Kademlia. Она будет реализована по протоколу ADNL.
Любой узел, участвующий в DHT, подобном Kademlia, обычно поддерживает таблицу маршрутизации Kademlia. В случае TON DHT он состоит из n = 256 шардчейнов, пронумерованных от 0 до n — 1. i-й сегмент будет содержать информацию о некоторых известных узлах (фиксированное количество t «лучших» узлов и, возможно, некоторые дополнительные кандидаты), которые лежат на расстоянии Kademlia от 2i до 2i+1 — 1 от адреса узла a32. Эта информация включает их (полупостоянные) адреса, IP-адреса и порты UDP, а также некоторую информацию о доступности, такую как время и задержка последнего пинга.
Когда узел Kademlia узнает о любом другом узле Kademlia в результате некоторого запроса, он включает его в подходящую корзину своей таблицы маршрутизации, сначала в качестве кандидата. Затем, если некоторые из «лучших» узлов в этом сегменте выходят из строя (например, не отвечают на запросы проверки связи в течение длительного времени), они могут быть заменены некоторыми из кандидатов. Таким образом, таблица маршрутизации Kademlia остается всегда заполненной.
Новые узлы из таблицы маршрутизации Kademlia также включаются в таблицу соседних узлов ADNL. Если часто используется «лучший» узел из группы таблицы маршрутизации Kademlia, для облегчения шифрования датаграмм может быть установлен канал.
Особенностью TON DHT является то, что таблица пытается выбрать узлы с наименьшими задержками приема-передачи в качестве «лучших» узлов для шардчейнов таблицы маршрутизации Kademlia.
Узел Kademlia обычно поддерживает следующие сетевые запросы:
• PING — проверяет доступность узла.
• STORE (ключ, значение) — просит узел сохранить значение в качестве значения для ключа key. Для TON DHT запросы STORE немного сложнее.
• FIND_NODE(key, l) — просит узел вернуть l ближайших к Kademlia известных узлов (из его таблицы маршрутизации Kademlia) ключу.
• FIND_VALUE(key, l) — То же, что и выше, но если узел знает значение, соответствующее ключу key, он просто возвращает это значение.
Когда какой-либо узел хочет найти значение ключа K, он сначала создает набор S из s’ узлов (для некоторого небольшого значения s’, скажем, s’= 5), ближайших к K 32 Если в сегменте достаточно много узлов, его можно дополнительно разделить, скажем, на восемь подсегментов в зависимости от четырех старших битов расстояния Kademlia. Это ускорит поиск DHT.
относительно расстояния Kademlia среди всех известных узлов (т. е. они взяты из таблицы маршрутизации Kademlia). Затем каждому из них отправляется запрос FIND_VALUE, и узлы, упомянутые в ответах, включаются в S. Затем узлам s из S, ближайшим к K, также отправляется запрос FIND_VALUE, если это не было сделано ранее, и процесс продолжается до тех пор, пока не будет найдено значение или пока множество S не перестанет расти. Это своего рода «направленный поиск» узла, ближайшего к K по отношению к расстоянию Kademlia.
Если необходимо установить значение некоторого ключа K, та же процедура выполняется для s’ ≥ s с запросами FIND_NODE вместо FIND_VALUE, чтобы найти s ближайших узлов к K. После этого всем этим узлам отправляются запросы STORE.
В реализации подобной Kademlia таблицы DHT есть некоторые менее важные детали (например, любой узел должен искать ближайшие к себе узлы, скажем, один раз в час, и повторно публиковать все сохраненные ключи к ним с помощью запросов STORE). Мы пока будем игнорировать эти детали.
Загрузка узла Kademlia
Когда узел Kademlia подключается к сети, он сначала заполняет свою таблицу маршрутизации Kademlia, просматривая свой собственный адрес. Во время этого процесса он определяет s ближайших к себе узлов. Он может загружать из них все известные им пары (ключ, значение) для заполнения своей части DHT.
Сохранение значений в TON DHT
Хранение значений в TON DHT немного отличается от обычной Kademlia-подобной таблицы DHT. Если необходимо сохранить значение, должен быть предоставлен не только сам ключ K для запроса STORE, но и его прообраз, то есть TL-сериализированная строка (с одним из нескольких предопределенных TL-конструкторов в начале), содержащую «описание» ключа. Это описание ключа позже сохраняется в узле вместе с ключом и значением.
Описание ключа описывает «тип» сохраняемого объекта, его «владельца» и соответствующие «правила обновления» в случае будущих обновлений. Владелец обычно идентифицируется открытым ключом, включенным в описание ключа. Если он включен, обычно будут приниматься только обновления, подписанные соответствующим закрытым ключом. «Тип» хранимого объекта — это обычно просто байтовая строка. Однако в некоторых случаях он может быть более сложным — например, описание входного туннеля или набор адресов узлов.
«Правила обновления» тоже могут быть разными. В некоторых случаях они просто разрешают замену старого значения новым значением, при условии, что новое значение подписано владельцем (подпись должна быть сохранена как часть значения, которое позже проверяется любыми другими узлами после того, как они получат значение этого ключа). В других случаях старое значение так или иначе влияет на новое значение. Например, оно может содержать порядковый номер, а старое значение перезаписывается только в том случае, если новый порядковый номер больше (для предотвращения атак повторного воспроизведения).
Еще один интересный случай, когда значение содержит список узлов — возможно, с их IP-адресами и портами или просто с соответствующими абстрактными адресами, — а «правило обновления» заключается во включении запрашивающей стороны в этот список при условии, что она может подтвердить свою идентичность.
Этот механизм можно использовать для создания распределенного «торрент-трекера», где все узлы, заинтересованные в определенном «торренте» (т. е. в определенном узле), могут найти другие узлы, которые заинтересованы в этом же торренте или уже имеют соответствующую копию.
TON Storage использует эту технологию для поиска узлов, у которых есть копия требуемого файла (например, зафиксированный снимок состояния шардчейна или старого блока). Однако более важная задача — создание «оверлейных подсетей многоадресной рассылки» и «сетевых специализированных групп». Идея состоит в том, что только некоторые узлы заинтересованы в обновлениях определенного шардчейна. Если количество шардчейнов становится очень большим, поиск даже одного узла, заинтересованного в одном и том же шарде, может стать сложным. Этот «распределенный торрент-трекер» предоставляет удобный способ поиска некоторых из этих узлов. Другой вариант — запросить их у валидатора, однако этот подход исключает масштабирование, и валидаторы могут решить не отвечать на такие запросы, поступающие от произвольных неизвестных узлов.
Большинство описанных до сих пор «типов ключей» имеют дополнительное 32-битное целое число, содержащееся в соответствующем TL-описании, обычно равное нулю. Однако если ключ был получен путем хеширования, это описание не может быть получено или обновлено в TON DHT, значение в этом удерживаемом ключе увеличивается, и делается новая попытка получения. Таким образом, невозможно «захватить» и «подвергнуть цензуре» ключ (то есть выполнить атаку с удержанием ключа) путем создания множества абстрактных адресов, находящихся рядом с атакуемым ключом, и управления соответствующими узлами DHT.
Услуги по определению местоположения
Для некоторых сервисов, расположенных в сети TON и доступных по (протоколам более высокого уровня, основанным на) TON ADNL, может понадобиться опубликовать их абстрактные адреса, чтобы их клиенты знали, где их найти.
Однако публикация абстрактного адреса сервиса в блокчейне TON может быть не самым лучшим подходом, поскольку может потребоваться довольно часто менять абстрактный адрес, и поэтому может иметь смысл предоставить несколько адресов в целях надежности или балансировки нагрузки.
Альтернативой является публикация открытого ключа в блокчейне TON и использование специального ключа DHT, указывающего этот открытый ключ в качестве его «владельца» в строке описания TL, что позволяет публиковать обновленный список абстрактных адресов сервиса. Это один из подходов, используемых в TON Services.
В большинстве случаев владельцы учетных записей блокчейна TON не хотят, чтобы их ассоциировали с абстрактными сетевыми адресами, особенно с IP-адресами, поскольку это может нарушить их конфиденциальность. Однако в некоторых случаях владелец учетной записи блокчейна TON может захотеть опубликовать один или несколько абстрактных адресов, по которым с ним можно связаться.
Типичный случай — это узел в «сети моментальных платежей» TON Payments, платформе для мгновенных переводов криптовалюты. Общедоступный узел TON Payments может захотеть не только установить платежные каналы с другими одноранговыми узлами, но также опубликовать абстрактный сетевой адрес, который можно использовать для последующей связи с ним для передачи платежей по уже установленным каналам.
Одним из вариантов может быть включение абстрактного сетевого адреса в смарт-контракт, создающий платежный канал. Более гибкий вариант — включить открытый ключ в смарт-контракт, а затем использовать DHT.
Наиболее естественным способом было бы использовать тот же закрытый ключ, который управляет учетной записью в блокчейне TON, для подписания и публикации обновлений в TON DHT об абстрактных адресах, связанных с этой учетной записью. Этот процесс практически совпадает с п. 3.2.12; однако для используемого ключа DHT потребуется специальное описание ключа, содержащее только идентификатор account_id, равный SHA256 «описания учетной записи», который содержит открытый ключ учетной записи. Подпись, включенная в значение этого ключа DHT, также будет содержать описание учетной записи.
Таким образом, становится доступным механизм определения абстрактных сетевых адресов некоторых владельцев учетных записей блокчейна TON.
Обратите внимание, что хотя таблица TON DHT и реализуется поверх TON ADNL, TON DHT сама используется TON ADNL для нескольких целей. Самая важная задача — найти узел или его контактные данные, начиная с 256-битного абстрактного адреса. Это необходимо, потому что TON ADNL должен иметь возможность отправлять датаграммы на произвольные 256-битные абстрактные адреса, даже если не предоставляется никакой дополнительной информации.
Для этого 256-битный абстрактный адрес просто просматривается как ключ в DHT. При этом либо находится узел с этим адресом (т. е. с использованием этого адреса в качестве общедоступного полупостоянного адреса DHT), и в этом случае можно узнать его IP-адрес и порт; либо может быть получено описание входного туннеля как значение рассматриваемого ключа, подписанное правильным закрытым ключом, и в этом случае это описание туннеля будет использоваться для отправки датаграмм ADNL предполагаемому получателю.
Обратите внимание: для того, чтобы сделать абстрактный адрес «общедоступным» (доступным с любых узлов в сети), его владелец должен либо использовать его как полупостоянный адрес DHT, либо опубликовать (в ключе DHT, равном рассматриваемому абстрактному адресу ) описание входного туннеля с другим его общедоступным абстрактным адресом (например, полупостоянным адресом) в качестве точки входа в туннель. Другой вариант — просто опубликовать IP-адрес и порт UDP.