05.03.2018
Bitcoin и Ethereum: что происходит на узлах, которые не занимаются добычей, и что с ними будет дальше?

В последнее время довольно часто говорят о перспективах блокчейн систем, о том, что в будущем блокчейн заменит классические платёжные системы, такие как, например, Visa или Mastercard, а затем, возможно, коренным образом изменит и юриспруденцию благодаря возможностям «умных» контрактов. Но, несмотря на все ожидания, полноценной и всеобъемлющей платёжной системы на блокчейне пока не создано. Оплата реальных товаров и услуг криптовалютами, как правило, осуществляется в тех случаях, когда на использование классических способов оплаты наложены какие-то ограничения. При этом значительная часть сделок с использованием криптовалют несёт спекулятивный характер.

Факторов, сдерживающих развитие блокчейн систем, безусловно, много. Они могут иметь как техническую, так и экономическую, политическую или даже психологическую природу. В данной статье будут рассмотрены только некоторые технические ограничения двух наиболее популярных блокчейн систем — Bitcoin и Ethereum.

Предполагается, что Вы уже знакомы с основными принципами работы этих систем. Если какие-то термины окажутся не совсем понятными, их объяснение можно найти в книге Mastering Bitcoin Андреаса Антонопулоса (в сети можно найти перевод на русский язык), и в статье о принципах работы Ethereum на Geektimes.

Стоит также отметить, что в последнее время на волне популярности блокчейн систем к ним стали относить некоторые распределённые хранилища данных, которые в исходном понимании термина блокчейн таковыми не являются, и поэтому, как правило, не обладают должным уровнем безопасности совместно с открытостью и независимостью. В данной статье под блокчейн системами мы будем понимать распределённые хранилища, которые удовлетворяют следующим требованиям:

Перспективы ускорения добычи блоков

В современных системах транзакции осуществляются значительно медленнее по сравнению с обычными платёжными системами. Наиболее популярные на сегодняшний день системы, в первую очередь, Bitcoin и Ethereum построены на использовании принципа доказательства работы (proof-of-work). Для подтверждения транзакции в таких системах требуется сначала дождаться, пока транзакция пройдёт очередь на добавление и будет зафиксирована в очередном блоке. Затем нужно ещё подождать некоторое время, в течение которого будет выполнен объём вычислительной работы, достаточный для гарантии того, что уже никто не сможет повторить эту работу самостоятельно с целью модификации добавленных данных. В системе Bitcoin обычно транзакция считается подтверждённой после добавления 6 блоков после блока, содержащего соответствующую транзакцию. Этот процесс занимает примерно один час. Что касается Ethereum, то здесь единого мнения относительно надёжного подтверждения нет: некоторые кошельки могут ждать подтверждения 5 блоков (около минуты), в то время как отдельные биржи могут требовать добавления нескольких сотен блоков для подтверждения.

Некоторые биржи могут осуществлять внутренние операции с криптовалютами значительно быстрее – за считанные доли секунды. Но эти транзакции являются внутренними. Они не заносятся в общий блокчейн, а хранятся в базе данных конкретной биржи. В основной блокчейн информация о переводах попадёт только при операциях ввода и вывода средств с биржи. Поэтому в дальнейшем мы не будем рассматривать внутренние транзакции биржи как блокчейн-транзакции.

Для совершения небольших покупок, ввиду низких рисков продавца, часто не требуется ждать подтверждения. Достаточно информации о том, что транзакция попала в сеть и добавлена в очередь. Но, если рассматривать систему в целом, основным элементом, ограничивающим производительность сети, по-прежнему остаётся добыча (mining) блоков, поскольку все отправленные транзакции всё равно рано или поздно должны быть добавлены в блоки. Сложность добычи не имеет под собой реальных физических оснований, а задаётся искусственно, чтобы обеспечить необходимое количество работы для надёжного подтверждения. В системе Bitcoin сложность добычи подбирается таким образом, чтобы среднее время добавления нового блока составляло приблизительно 10 минут. Если блоки начинают добываться быстрее, сложность увеличивается, если дольше — снижается. Частота добавления блоков в Ethereum выше – новый блок добавляется примерно каждые 15 секунд.

При необходимости частоту добавления новых блоков можно повысить, снизив сложность добычи, или же вообще отказаться от процесса добычи, переключив систему на работу в соответствии с принципом доказательства доли владения (proof-of-stake). Однако и в том и в другом случае вероятность одновременного нахождения новых блоков возрастёт, что приведёт к росту числа ветвлений цепи (fork) и соответствующим неудобствам. Критическим временем добавления блока здесь будет являться время, соответствующее характерному времени распространения блока по сети. После превышения данного порога майнеры слишком часто будут получать информацию о новом добытом блоке уже после того, как добудут его сами (возможно, включив в него другой набор транзакций) и отправят в сеть. Таким образом, добавление почти каждого блока будет сопровождаться ветвлением, что сделает невозможным нормальное функционирование сети. Время распространения данных по сети между разными континентами можно грубо оценить величиной 100 мс. Таким образом, скорость добавления блоков в Bitcoin можно повысить не более чем в раз, а в Ethereum – в раз.

Особенности хранения базы транзакций на полных узлах

Повышать число обрабатываемых транзакций можно не только за счёт увеличения частоты добычи новых блоков, но и за счёт увеличения их размера. В этом случае рано или поздно также появятся определённые ограничения. Одним из наиболее простых ограничений является количество используемого дискового пространства. Работа с данными в Bitcoin и Ethereum устроена по-разному, поэтому рассматривать их имеет смысл отдельно друг от друга.

Bitcoin

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

Рисунок 1. В блокчейне Bitcoin не хранится информация о текущем состоянии счетов, только информация о списании и зачислении средств в рамках конкретных транзакций. Чтобы узнать текущий баланс, нужно просуммировать все транзакции с непотраченными выходами.

На данный момент размер блокчейна Bitcoin превышает 150 Гбайт и увеличивается со скоростью примерно 50 Гбайт/год. Стоит отметить, что этот рост связан не столько с приходом новых пользователей, сколько с совершением транзакций уже существующими пользователями. Поскольку каждый день в хранилище добавляется информация о новых транзакциях, и при этом информация о старых транзакциях не удаляется, объём базы будет только расти.

Рисунок 2. Зависимость размера блокчкйна Bitcoin от времени. Источник:

blockchain.info.

Далеко не все пользователи готовы выделить на своём персональном компьютере несколько сотен гигабайт дискового пространства для хранения блокчейна. Нужно учесть, что это не просто файлы, хранящиеся на диске, а база данных, которая при добавлении новых блоков осуществляет перестроение части данных для обеспечения эффективности их хранения. В клиентах Bitcoin чаще всего используется NoSQL база LevelDB, построенная на LSM деревьях.

Проверку транзакций можно оптимизировать за счёт использования отдельной базы транзакций с непотраченными выходами (UTXO), так как именно эти данные представляют наибольший интерес. Теоретически, проверив подлинность UTXO, информацию о старых транзакциях из общей базы можно удалить с целью оптимизации. Однако оставшаяся база данных всё равно займёт не один гигабайт дискового пространства. Интенсивность обращений к диску при этом уменьшится несильно. Размер базы, конечно, будет на порядок меньше, но помимо добавления транзакций в этом случае появятся и удаления UTXO с закрывшимися выходами. Таким образом, поддержание так называемого полного узла сети вызывает определённые неудобства у обычных пользователей. Есть мнение, что значительная число полных узлов Bitcoin уже сейчас размещена в дата-центрах.

Для работы ПО «кошелька» и отправки транзакций хранение полной базы данных не является обязательным условием. Обычно достаточно «лёгкого» узла, который будет запрашивать необходимые для работы данные у других узлов по сети. Так работают многие программы «кошельки» и клиенты для мобильных устройств. Однако такой подход не обеспечивает абсолютной надёжности: приходится доверять данным, полученным по сети. Запрашивая дополнительные, избыточные данные из различных источников, можно добиться повышения надёжности, но надёжность при этом будет иметь вероятностный характер. То же относится и к анонимности: запрашивая данные об определённых транзакциях по сети, пользователь фактически выдаёт область своих интересов. За счёт запроса избыточных данных область интересов можно замаскировать, но лишь с определённой вероятностью. Отказ пользователей от поддержания полных узлов не является благоприятным и для сети в целом, так как в ней становится проще набрать критическое количество полных узлов, позволяющее оказывать влияние на процесс обработки транзакций.

Ethereum

В Ethereum есть понятие состояния (state) аккаунта, которое включает в себя состояние счёта. В блокчейне хранятся изменения таких состояний. Узлы Ethereum хранят актуальные состояния аккаунтов и при получении новых блоков применяют изменения к имеющимся состояниям, поддерживая тем самым их актуальность. Для обеспечения надёжности хранить старые состояния не требуется, достаточно последнего актуального состояния и уверенности в том, что оно корректно. Благодаря этому в Ethereum не два а три типа узлов:

Более подробная информация о видах синхронизации приведена в статье на dev.to.

Проблемы архивных узлов Ethereum аналогичны проблемам полных узлов Bitcoin: размер базы данных исчисляется сотнями гигабайт и, если темп роста количества данных сохранится, то уже до конца 2018 года полная база данных перестанет помещаться на одном стандартном жёстком диске или твердотельном накопителе.

Рисунок 3. Зависимость размера блокчейна Ethereum от времени (для сравнения также приведена зависимость для Bitcoin). Источник: daniel.net.nz.

Но, как уже упоминалось выше, для безопасного проведения транзакций достаточно полного Ethereum узла с «обстриженной» базой данных, которая на данный момент занимает «всего» 40 Гбайт.

Рисунок 4. Зависимость размера базы данных полного узла Ethereum от времени. Источник: etherscan.io.

Однако на практике не всё оказывается так просто. В результате экспериментов с одной из наиболее популярных реализаций клиента Ethereum – Geth (Go Ethereum), — в январе 2018 года оказалось, что примерно за две недели работы клиента размер базы данных увеличился с 40 Гбайт до 80 Гбайт. Дальнейшее исследование показало, что после завершения синхронизации базы данный клиент переходит в режим архивного узла. То есть из базы данных не удаляется информация об устаревших состояниях аккаунтов, что приводит к увеличению размера базы, который относительно быстро может превысить несколько сотен гигабайт (см. рисунок 3). Разработчики о проблеме знают, но тикет закрыт почти полгода назад без принятия каких-либо мер по решению проблемы. Единственная практическая рекомендация заключается в следующем: удалить базу данных и загрузить её заново в режиме «быстрой» синхронизации (может занять несколько дней). В этом случае загруженная база, действительно, окажется меньше, но после завершения синхронизации клиент опять переключится в режим полной синхронизации и размер базы данных опять начнёт быстро увеличиваться.

Создаётся впечатление, что один из наиболее популярных клиентов Ethereum не рассчитан на длительное использования в безопасном режиме, а ориентирован лишь на майнеров, для работы которых требуется полная база, и спекулянтов, которых интересует только стоимость криптовалюты, а не безопсаность и надёжность использования соответствующего ПО.

Виртуальная машина Ethereum

Как известно, Ethereum – это не только средство для осуществления платежей, но и распределённая виртуальная машина, позволяющая выполнять «умные» контракты. Такие контракты являются простыми программами, исполняемыми на специальной виртуальной машине. С учётом того, что каждый полный или архивный узел должен последовательно выполнить все поступающие вызовы таких контрактов, разумно предположить, что дальнейшее развитие Ethereum ограниченно именно возможностями современных компьютеров по обработке большого числа вызовов таких контрактов.

Рисунок 5. Зависимость количества транзакций в одном блоке блокчейна Ethereum от времени (скорость добавления блоков практически постоянна и равна примерно четырём блокам в минуту).

Оценить рост вычислительной сложности обработки «умных» контрактов можно, загрузив полную базу данных. Среди прочего в полной базе хранятся трассы выполнения всех вызовов всех контрактов в операциях виртуальной машины Ethereum (EVM – Ethereum Virtual Machine). Список используемых команд можно посмотреть, например, на GitHub.

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

Рисунок 6. Зависимость количества вызовов операции вычисления хеш-функции sha3 в контрактах Ethereum от времени.

Рисунок 7. Зависимость количества вызовов различных операций обращения к памяти в контрактах Ethereum от времени.

Рисунок 8. Зависимость количества системных вызовов в контрактах Ethereum от времени.

Как видно из графиков, на данный момент виртуальная машина Ethereum для своей работы не требует большого количества ресурсов: за секунду осуществляется вычисление примерно ста хеш-функций (с учётом скорости добычи в 4 блока в минуту), несколько сотен доступов в память различного вида и порядка 10 системных вызовов. Даже если учесть десятикратный рост в течение года, проблемы с хранением данных, возникнут гораздо раньше (см. предыдущие разделы).

Несмотря на то, что виртуальная машина Ethereum не должна потреблять много ресурсов в процессе своей работы, клиент Geth почти полностью загружает ЦП и достаточно активно использует память и жёсткий диск. База данных Ethereum содержит значительное число записей, поэтому, возможно, для работы с ней требуется достаточно много ресурсов. Можно грубо оценить частоту обращений к диску. При выполнении транзакции нужно проверить, что средства отправителя зафиксированы в блокчейне. Для этого нужно совершить поиск в базе данных на диске. С учётом логарифмического времени поиска и накладных расходов, связанных со структурой LSM деревьев, одну операцию поиска в базе можно оценить как 100 случайных обращений к диску. В каждом блоке содержится приблизительно 100 транзакций (см. предыдущий раздел). В минуту добавляется приблизительно 4 блока. Таким образом, только для проверки транзакций в минуту нужно совершить случайных обращений к диску.

Для проверки этой оценки и выявления наиболее сложной с вычислительной точки зрения части клиента было проведено его профилирование с помощью предусмотренной разработчиками функции записи трассы выполнения. Для анализа записанной трассы использовались стандартные средства языка go (go tool trace).

На диаграмме ниже приведены результаты измерения времени работы различных горутин (аналог потоков в языке go) в процессе работы клиента Geth после завершения полной синхронизации. Измерения проводились в течение 60 секунд.

Рисунок 9. Время выполнения 10 наиболее требовательных к ресурсам горутин клиента Geth после завершения полной синхронизации в случае размещения базы данных на жёстком диске. Время измерения – 1 минута.

Из диаграммы видно, что большую часть времени занимает работа загрузчика, который должен импортировать блоки, проверять транзакции, выполнять соответствующие вызовы контрактов с использованием виртуальной машины и обновлять соответствующие состояния в базе данных. В силу небольшого количества данных (4 блока приблизительно по 100 транзакций в минуту), сама загрузка не должна занимать много времени. Работа виртуальной машины, как оказалось, тоже. Более подробный анализ профиля показал, что за время измерения (1 минута) было совершено около 100 000 системных вызовов, большая часть которых представляет собой обращения к файлам базы данных LevelDB, которые располагались на жёстком диске (то есть оценка, приведённая выше, оказалась верной). Таким образом, среднее время между соседними обращениями к файлам составляет мксвызововмкс, что по порядку величины сопоставимо со временем случайного доступа к жёсткому диску. Исходя из этого, можно сделать вывод о том, что обращения к диску и являются в данном случае наиболее узким местом. Это предположение имеет и экспериментальное подтверждение в виде стабильно высокой загрузки диска в процессе работы клиента.

Ситуация с rpc.ServerRequest (задача, которая заняла второе место по времени выполнения) аналогичная – достаточно большое число системных вызовов, в момент совершения которых верхняя часть стека имеет вид:

syscall.Pread:1372
os.(*File).pread:238
os.(*File).ReadAt:120
github.com/ethereum/go-ethereum/vendor/github.com/syndtr/goleveldb/leveldb/table.(*Reader).readRawBlock:564
github.com/ethereum/go-ethereum/vendor/github.com/syndtr/goleveldb/leveldb/table.(*Reader).readFilterBlock:653
* * *

На третьем месте по времени выполнения находится обслуживание базы данных – leveldb.tCompaction. Далее следуют накладные расходы, связанные со сборкой мусора в языке go. Выполнение остальных горутин занимает пренебрежимо мало времени.

Таким образом, в случае хранения полной базы на жёстком диске (не SSD), ограничивающим фактором является работа базы данных, а точнее файловый ввод-вывод. Поэтому для обеспечения эффективной работы полного узла рекомендуется использовать твердотельные накопители, которые теоретически могут ускорить работу базы данных на 2-3 порядка. Дополнительно снизить нагрузку на базу данных можно путём использования быстрой синхронизации. В этом случае размер базы данных должен быть на порядок меньше (десятки гигабайт вместо сотен), поэтому обновление данных в такой базе должно осуществляться быстрее, в том числе и за счёт меньшего количества обращений к жёсткому диску. Результаты профилирования клиента Geth в процессе добавления блоков после быстрой синхронизации в условиях размещения базы на SSD приведены на диаграмме ниже. Измерения проводились в течение 10 минут.

Рисунок 10. Время выполнения 10 наиболее требовательных к ресурсам горутин в клиенте Geth после завершения быстрой синхронизации в случае размещения базы данных на твердотельном накопителе. Время измерения – 10 минут.

В результате профилирования оказалось, что больше всего времени занимает выполнение горутины miner.(*worker).update. На первый взгляд результаты кажутся удивительными, поскольку перед запуском профилирования добыча была отключена путём явного вызова соответствующей функции API. Более детальный анализ результатов профилирования и просмотра исходного кода Geth показал, что, не смотря на отключенную добычу, майнер продолжает обрабатывать поступающие транзакции и добавлять их в свою базу данных. Таким образом, реальной добычи здесь нет, и большая часть работы майнера сводится к работе с базой данных и системным вызовам для обращения к соответствующим файлам.

На втором месте по времени выполнения находится обслуживание базы данных. Далее идут другие задачи, которые в той или иной мере используют базу данных.

Интересно, что хеширование (горутина (*hasher).hashChildren) в среднем занимает в 30 раз меньше времени, чем работа с базой данных транзакций майнера. При этом, если майнер всё время работает в рамках одной горутины, то для вычисления хешей горутины каждый раз создаются и уничтожаются со всеми сопутствующими накладными расходами. В секунду создаётся и уничтожается несколько сотен таких горутин. Таким образом, в случае ускорения базы данных и увеличения количества добавляемых транзакций, вычисление хеш-функций, вероятно, станет одним из основных узких мест.

Хеширование используется не только для подтверждения и проверки блоков в системах, основанных на принципе подтверждения работой (proof-of-work), но и лежит в основе хранения данных в блоках и проверки их целостности. Поэтому проблема вычисления хеш-функций возникнет и в системах, основанных на доказательстве доли владения (proof-of-stake). Решением данной проблемы может стать использование ускорителей, которые могут быть построены как на основе видеокарт общего назначения, так и на основе специализированных сопроцессоров или микросхем, которые уже сегодня применяются для добычи в системе Bitcoin.

Если не учитывать процесс добычи, как искусственно созданные сложности, наиболее узким местом с точки зрения производительности в современных блокчейн системах являются базы данных. Если темпы роста количества совершаемых транзакций не снизятся, то, вероятно, уже до конца 2018 года полные цепочки блоков наиболее популярных блокчейн систем перестанут помещаться на один жёсткий диск. В одном из наиболее популярных клиентов системы Ethereum до сих пор нет нормальной поддержки полного узла в режиме «подстриженных» деревьев (pruned mode). В системе Bitcoin такие режимы явным образом не предусмотрены.

При работе с базами данных в блокчейн системах важен не только объём диска, но и его скорость. Уже сейчас в случае размещения данных на обычных жёстких дисках значительная часть времени тратится на чтение и запись данных. Вероятно, уже скоро полные узлы смогут работать только на твердотельных накопителях. В дальнейшем, вероятно, потребуется переход к массивам SSD и использованию более сложных баз данных, обеспечивающих более высокую производительность за счёт параллельной работы с большим числом накопителей.

Что касается технических ограничений, не связанных с базами данных, то наибольшим из них, скорее всего, окажется вычисление хеш-функций. Данная проблема может быть решена за счёт использования видеокарт или других специализированных устройств.

Поэтому многим пользователям, которые сегодня поддерживают полные узлы на своих персональных компьютерах, в скором времени, возможно, придётся отказаться от них в пользу «лёгких» и при этом менее безопасных клиентов. Таким образом, число полных узлов в сети сократится, а размещены они будут, скорее всего, в дата-центрах крупных компаний, которые могут позволить себе высокопроизводительные хранилища данных, сервера с действительно большим количеством оперативной памяти для оптимизации работы баз данных и специализированные ускорители для вычисления хеш-функций. Сумеют ли крупные компании объединиться в общую сеть или же независимо друг от друга будут поддерживать несколько различных систем, и как именно будет организована работа с такими системами, пока непонятно. Однако очевидно, что такие системы будут уже не столь децентрализованы и независимы, как, например, современный Bitcoin.

Возможен и другой подход, заключающийся в распределённом хранении отдельных частей блокчейна на пользовательских устройствах. В этом случае пользователям потребуется значительно меньший объём дискового пространства, однако возрастёт нагрузка на сеть, поскольку большая часть данных будет запрашиваться у других пользователей. Достаточный уровень безопасности при этом может быть достигнут только при значительной избыточности запрашиваемых данных при условии достаточного количества независимых источников. Для организации взаимодействия между узлами, хранящими различные части базы данных могут потребоваться специальные узлы-маршрутизаторы (возможно, такие узлы будут устроены аналогично BitTorrent-треккерам), что также приведёт к снижению децентрализации сети.

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


Оригинал статьи

Bitcoin и Ethereum: что происходит на узлах, которые не занимаются добычей, и что с ними будет дальше?

В последнее время довольно часто говорят о перспективах блокчейн систем, о том, что в будущем блокчейн заменит классические платёжные системы, такие как, например, Visa или Mastercard, а затем, возможно, коренным образом изменит и юриспруденцию благодаря возможностям «умных» контрактов. Но, несмотря на все ожидания, полноценной и всеобъемлющей платёжной системы на блокчейне пока не создано. Оплата реальных товаров и услуг криптовалютами, как правило, осуществляется в тех случаях, когда на использование классических способов оплаты наложены какие-то ограничения. При этом значительная часть сделок с использованием криптовалют несёт спекулятивный характер.

Факторов, сдерживающих развитие блокчейн систем, безусловно, много. Они могут иметь как техническую, так и экономическую, политическую или даже психологическую природу. В данной статье будут рассмотрены только некоторые технические ограничения двух наиболее популярных блокчейн систем — Bitcoin и Ethereum.

Предполагается, что Вы уже знакомы с основными принципами работы этих систем. Если какие-то термины окажутся не совсем понятными, их объяснение можно найти в книге Mastering Bitcoin Андреаса Антонопулоса (в сети можно найти перевод на русский язык), и в статье о принципах работы Ethereum на Geektimes.

Стоит также отметить, что в последнее время на волне популярности блокчейн систем к ним стали относить некоторые распределённые хранилища данных, которые в исходном понимании термина блокчейн таковыми не являются, и поэтому, как правило, не обладают должным уровнем безопасности совместно с открытостью и независимостью. В данной статье под блокчейн системами мы будем понимать распределённые хранилища, которые удовлетворяют следующим требованиям:

Перспективы ускорения добычи блоков

В современных системах транзакции осуществляются значительно медленнее по сравнению с обычными платёжными системами. Наиболее популярные на сегодняшний день системы, в первую очередь, Bitcoin и Ethereum построены на использовании принципа доказательства работы (proof-of-work). Для подтверждения транзакции в таких системах требуется сначала дождаться, пока транзакция пройдёт очередь на добавление и будет зафиксирована в очередном блоке. Затем нужно ещё подождать некоторое время, в течение которого будет выполнен объём вычислительной работы, достаточный для гарантии того, что уже никто не сможет повторить эту работу самостоятельно с целью модификации добавленных данных. В системе Bitcoin обычно транзакция считается подтверждённой после добавления 6 блоков после блока, содержащего соответствующую транзакцию. Этот процесс занимает примерно один час. Что касается Ethereum, то здесь единого мнения относительно надёжного подтверждения нет: некоторые кошельки могут ждать подтверждения 5 блоков (около минуты), в то время как отдельные биржи могут требовать добавления нескольких сотен блоков для подтверждения.

Некоторые биржи могут осуществлять внутренние операции с криптовалютами значительно быстрее – за считанные доли секунды. Но эти транзакции являются внутренними. Они не заносятся в общий блокчейн, а хранятся в базе данных конкретной биржи. В основной блокчейн информация о переводах попадёт только при операциях ввода и вывода средств с биржи. Поэтому в дальнейшем мы не будем рассматривать внутренние транзакции биржи как блокчейн-транзакции.

Для совершения небольших покупок, ввиду низких рисков продавца, часто не требуется ждать подтверждения. Достаточно информации о том, что транзакция попала в сеть и добавлена в очередь. Но, если рассматривать систему в целом, основным элементом, ограничивающим производительность сети, по-прежнему остаётся добыча (mining) блоков, поскольку все отправленные транзакции всё равно рано или поздно должны быть добавлены в блоки. Сложность добычи не имеет под собой реальных физических оснований, а задаётся искусственно, чтобы обеспечить необходимое количество работы для надёжного подтверждения. В системе Bitcoin сложность добычи подбирается таким образом, чтобы среднее время добавления нового блока составляло приблизительно 10 минут. Если блоки начинают добываться быстрее, сложность увеличивается, если дольше — снижается. Частота добавления блоков в Ethereum выше – новый блок добавляется примерно каждые 15 секунд.

При необходимости частоту добавления новых блоков можно повысить, снизив сложность добычи, или же вообще отказаться от процесса добычи, переключив систему на работу в соответствии с принципом доказательства доли владения (proof-of-stake). Однако и в том и в другом случае вероятность одновременного нахождения новых блоков возрастёт, что приведёт к росту числа ветвлений цепи (fork) и соответствующим неудобствам. Критическим временем добавления блока здесь будет являться время, соответствующее характерному времени распространения блока по сети. После превышения данного порога майнеры слишком часто будут получать информацию о новом добытом блоке уже после того, как добудут его сами (возможно, включив в него другой набор транзакций) и отправят в сеть. Таким образом, добавление почти каждого блока будет сопровождаться ветвлением, что сделает невозможным нормальное функционирование сети. Время распространения данных по сети между разными континентами можно грубо оценить величиной 100 мс. Таким образом, скорость добавления блоков в Bitcoin можно повысить не более чем в раз, а в Ethereum – в раз.

Особенности хранения базы транзакций на полных узлах

Повышать число обрабатываемых транзакций можно не только за счёт увеличения частоты добычи новых блоков, но и за счёт увеличения их размера. В этом случае рано или поздно также появятся определённые ограничения. Одним из наиболее простых ограничений является количество используемого дискового пространства. Работа с данными в Bitcoin и Ethereum устроена по-разному, поэтому рассматривать их имеет смысл отдельно друг от друга.

Bitcoin

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

Рисунок 1. В блокчейне Bitcoin не хранится информация о текущем состоянии счетов, только информация о списании и зачислении средств в рамках конкретных транзакций. Чтобы узнать текущий баланс, нужно просуммировать все транзакции с непотраченными выходами.

На данный момент размер блокчейна Bitcoin превышает 150 Гбайт и увеличивается со скоростью примерно 50 Гбайт/год. Стоит отметить, что этот рост связан не столько с приходом новых пользователей, сколько с совершением транзакций уже существующими пользователями. Поскольку каждый день в хранилище добавляется информация о новых транзакциях, и при этом информация о старых транзакциях не удаляется, объём базы будет только расти.

Рисунок 2. Зависимость размера блокчкйна Bitcoin от времени. Источник:

blockchain.info.

Далеко не все пользователи готовы выделить на своём персональном компьютере несколько сотен гигабайт дискового пространства для хранения блокчейна. Нужно учесть, что это не просто файлы, хранящиеся на диске, а база данных, которая при добавлении новых блоков осуществляет перестроение части данных для обеспечения эффективности их хранения. В клиентах Bitcoin чаще всего используется NoSQL база LevelDB, построенная на LSM деревьях.

Проверку транзакций можно оптимизировать за счёт использования отдельной базы транзакций с непотраченными выходами (UTXO), так как именно эти данные представляют наибольший интерес. Теоретически, проверив подлинность UTXO, информацию о старых транзакциях из общей базы можно удалить с целью оптимизации. Однако оставшаяся база данных всё равно займёт не один гигабайт дискового пространства. Интенсивность обращений к диску при этом уменьшится несильно. Размер базы, конечно, будет на порядок меньше, но помимо добавления транзакций в этом случае появятся и удаления UTXO с закрывшимися выходами. Таким образом, поддержание так называемого полного узла сети вызывает определённые неудобства у обычных пользователей. Есть мнение, что значительная число полных узлов Bitcoin уже сейчас размещена в дата-центрах.

Для работы ПО «кошелька» и отправки транзакций хранение полной базы данных не является обязательным условием. Обычно достаточно «лёгкого» узла, который будет запрашивать необходимые для работы данные у других узлов по сети. Так работают многие программы «кошельки» и клиенты для мобильных устройств. Однако такой подход не обеспечивает абсолютной надёжности: приходится доверять данным, полученным по сети. Запрашивая дополнительные, избыточные данные из различных источников, можно добиться повышения надёжности, но надёжность при этом будет иметь вероятностный характер. То же относится и к анонимности: запрашивая данные об определённых транзакциях по сети, пользователь фактически выдаёт область своих интересов. За счёт запроса избыточных данных область интересов можно замаскировать, но лишь с определённой вероятностью. Отказ пользователей от поддержания полных узлов не является благоприятным и для сети в целом, так как в ней становится проще набрать критическое количество полных узлов, позволяющее оказывать влияние на процесс обработки транзакций.

Ethereum

В Ethereum есть понятие состояния (state) аккаунта, которое включает в себя состояние счёта. В блокчейне хранятся изменения таких состояний. Узлы Ethereum хранят актуальные состояния аккаунтов и при получении новых блоков применяют изменения к имеющимся состояниям, поддерживая тем самым их актуальность. Для обеспечения надёжности хранить старые состояния не требуется, достаточно последнего актуального состояния и уверенности в том, что оно корректно. Благодаря этому в Ethereum не два а три типа узлов:

Более подробная информация о видах синхронизации приведена в статье на dev.to.

Проблемы архивных узлов Ethereum аналогичны проблемам полных узлов Bitcoin: размер базы данных исчисляется сотнями гигабайт и, если темп роста количества данных сохранится, то уже до конца 2018 года полная база данных перестанет помещаться на одном стандартном жёстком диске или твердотельном накопителе.

Рисунок 3. Зависимость размера блокчейна Ethereum от времени (для сравнения также приведена зависимость для Bitcoin). Источник: daniel.net.nz.

Но, как уже упоминалось выше, для безопасного проведения транзакций достаточно полного Ethereum узла с «обстриженной» базой данных, которая на данный момент занимает «всего» 40 Гбайт.

Рисунок 4. Зависимость размера базы данных полного узла Ethereum от времени. Источник: etherscan.io.

Однако на практике не всё оказывается так просто. В результате экспериментов с одной из наиболее популярных реализаций клиента Ethereum – Geth (Go Ethereum), — в январе 2018 года оказалось, что примерно за две недели работы клиента размер базы данных увеличился с 40 Гбайт до 80 Гбайт. Дальнейшее исследование показало, что после завершения синхронизации базы данный клиент переходит в режим архивного узла. То есть из базы данных не удаляется информация об устаревших состояниях аккаунтов, что приводит к увеличению размера базы, который относительно быстро может превысить несколько сотен гигабайт (см. рисунок 3). Разработчики о проблеме знают, но тикет закрыт почти полгода назад без принятия каких-либо мер по решению проблемы. Единственная практическая рекомендация заключается в следующем: удалить базу данных и загрузить её заново в режиме «быстрой» синхронизации (может занять несколько дней). В этом случае загруженная база, действительно, окажется меньше, но после завершения синхронизации клиент опять переключится в режим полной синхронизации и размер базы данных опять начнёт быстро увеличиваться.

Создаётся впечатление, что один из наиболее популярных клиентов Ethereum не рассчитан на длительное использования в безопасном режиме, а ориентирован лишь на майнеров, для работы которых требуется полная база, и спекулянтов, которых интересует только стоимость криптовалюты, а не безопсаность и надёжность использования соответствующего ПО.

Виртуальная машина Ethereum

Как известно, Ethereum – это не только средство для осуществления платежей, но и распределённая виртуальная машина, позволяющая выполнять «умные» контракты. Такие контракты являются простыми программами, исполняемыми на специальной виртуальной машине. С учётом того, что каждый полный или архивный узел должен последовательно выполнить все поступающие вызовы таких контрактов, разумно предположить, что дальнейшее развитие Ethereum ограниченно именно возможностями современных компьютеров по обработке большого числа вызовов таких контрактов.

Рисунок 5. Зависимость количества транзакций в одном блоке блокчейна Ethereum от времени (скорость добавления блоков практически постоянна и равна примерно четырём блокам в минуту).

Оценить рост вычислительной сложности обработки «умных» контрактов можно, загрузив полную базу данных. Среди прочего в полной базе хранятся трассы выполнения всех вызовов всех контрактов в операциях виртуальной машины Ethereum (EVM – Ethereum Virtual Machine). Список используемых команд можно посмотреть, например, на GitHub.

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

Рисунок 6. Зависимость количества вызовов операции вычисления хеш-функции sha3 в контрактах Ethereum от времени.

Рисунок 7. Зависимость количества вызовов различных операций обращения к памяти в контрактах Ethereum от времени.

Рисунок 8. Зависимость количества системных вызовов в контрактах Ethereum от времени.

Как видно из графиков, на данный момент виртуальная машина Ethereum для своей работы не требует большого количества ресурсов: за секунду осуществляется вычисление примерно ста хеш-функций (с учётом скорости добычи в 4 блока в минуту), несколько сотен доступов в память различного вида и порядка 10 системных вызовов. Даже если учесть десятикратный рост в течение года, проблемы с хранением данных, возникнут гораздо раньше (см. предыдущие разделы).

Несмотря на то, что виртуальная машина Ethereum не должна потреблять много ресурсов в процессе своей работы, клиент Geth почти полностью загружает ЦП и достаточно активно использует память и жёсткий диск. База данных Ethereum содержит значительное число записей, поэтому, возможно, для работы с ней требуется достаточно много ресурсов. Можно грубо оценить частоту обращений к диску. При выполнении транзакции нужно проверить, что средства отправителя зафиксированы в блокчейне. Для этого нужно совершить поиск в базе данных на диске. С учётом логарифмического времени поиска и накладных расходов, связанных со структурой LSM деревьев, одну операцию поиска в базе можно оценить как 100 случайных обращений к диску. В каждом блоке содержится приблизительно 100 транзакций (см. предыдущий раздел). В минуту добавляется приблизительно 4 блока. Таким образом, только для проверки транзакций в минуту нужно совершить случайных обращений к диску.

Для проверки этой оценки и выявления наиболее сложной с вычислительной точки зрения части клиента было проведено его профилирование с помощью предусмотренной разработчиками функции записи трассы выполнения. Для анализа записанной трассы использовались стандартные средства языка go (go tool trace).

На диаграмме ниже приведены результаты измерения времени работы различных горутин (аналог потоков в языке go) в процессе работы клиента Geth после завершения полной синхронизации. Измерения проводились в течение 60 секунд.

Рисунок 9. Время выполнения 10 наиболее требовательных к ресурсам горутин клиента Geth после завершения полной синхронизации в случае размещения базы данных на жёстком диске. Время измерения – 1 минута.

Из диаграммы видно, что большую часть времени занимает работа загрузчика, который должен импортировать блоки, проверять транзакции, выполнять соответствующие вызовы контрактов с использованием виртуальной машины и обновлять соответствующие состояния в базе данных. В силу небольшого количества данных (4 блока приблизительно по 100 транзакций в минуту), сама загрузка не должна занимать много времени. Работа виртуальной машины, как оказалось, тоже. Более подробный анализ профиля показал, что за время измерения (1 минута) было совершено около 100 000 системных вызовов, большая часть которых представляет собой обращения к файлам базы данных LevelDB, которые располагались на жёстком диске (то есть оценка, приведённая выше, оказалась верной). Таким образом, среднее время между соседними обращениями к файлам составляет мксвызововмкс, что по порядку величины сопоставимо со временем случайного доступа к жёсткому диску. Исходя из этого, можно сделать вывод о том, что обращения к диску и являются в данном случае наиболее узким местом. Это предположение имеет и экспериментальное подтверждение в виде стабильно высокой загрузки диска в процессе работы клиента.

Ситуация с rpc.ServerRequest (задача, которая заняла второе место по времени выполнения) аналогичная – достаточно большое число системных вызовов, в момент совершения которых верхняя часть стека имеет вид:

syscall.Pread:1372
os.(*File).pread:238
os.(*File).ReadAt:120
github.com/ethereum/go-ethereum/vendor/github.com/syndtr/goleveldb/leveldb/table.(*Reader).readRawBlock:564
github.com/ethereum/go-ethereum/vendor/github.com/syndtr/goleveldb/leveldb/table.(*Reader).readFilterBlock:653
* * *

На третьем месте по времени выполнения находится обслуживание базы данных – leveldb.tCompaction. Далее следуют накладные расходы, связанные со сборкой мусора в языке go. Выполнение остальных горутин занимает пренебрежимо мало времени.

Таким образом, в случае хранения полной базы на жёстком диске (не SSD), ограничивающим фактором является работа базы данных, а точнее файловый ввод-вывод. Поэтому для обеспечения эффективной работы полного узла рекомендуется использовать твердотельные накопители, которые теоретически могут ускорить работу базы данных на 2-3 порядка. Дополнительно снизить нагрузку на базу данных можно путём использования быстрой синхронизации. В этом случае размер базы данных должен быть на порядок меньше (десятки гигабайт вместо сотен), поэтому обновление данных в такой базе должно осуществляться быстрее, в том числе и за счёт меньшего количества обращений к жёсткому диску. Результаты профилирования клиента Geth в процессе добавления блоков после быстрой синхронизации в условиях размещения базы на SSD приведены на диаграмме ниже. Измерения проводились в течение 10 минут.

Рисунок 10. Время выполнения 10 наиболее требовательных к ресурсам горутин в клиенте Geth после завершения быстрой синхронизации в случае размещения базы данных на твердотельном накопителе. Время измерения – 10 минут.

В результате профилирования оказалось, что больше всего времени занимает выполнение горутины miner.(*worker).update. На первый взгляд результаты кажутся удивительными, поскольку перед запуском профилирования добыча была отключена путём явного вызова соответствующей функции API. Более детальный анализ результатов профилирования и просмотра исходного кода Geth показал, что, не смотря на отключенную добычу, майнер продолжает обрабатывать поступающие транзакции и добавлять их в свою базу данных. Таким образом, реальной добычи здесь нет, и большая часть работы майнера сводится к работе с базой данных и системным вызовам для обращения к соответствующим файлам.

На втором месте по времени выполнения находится обслуживание базы данных. Далее идут другие задачи, которые в той или иной мере используют базу данных.

Интересно, что хеширование (горутина (*hasher).hashChildren) в среднем занимает в 30 раз меньше времени, чем работа с базой данных транзакций майнера. При этом, если майнер всё время работает в рамках одной горутины, то для вычисления хешей горутины каждый раз создаются и уничтожаются со всеми сопутствующими накладными расходами. В секунду создаётся и уничтожается несколько сотен таких горутин. Таким образом, в случае ускорения базы данных и увеличения количества добавляемых транзакций, вычисление хеш-функций, вероятно, станет одним из основных узких мест.

Хеширование используется не только для подтверждения и проверки блоков в системах, основанных на принципе подтверждения работой (proof-of-work), но и лежит в основе хранения данных в блоках и проверки их целостности. Поэтому проблема вычисления хеш-функций возникнет и в системах, основанных на доказательстве доли владения (proof-of-stake). Решением данной проблемы может стать использование ускорителей, которые могут быть построены как на основе видеокарт общего назначения, так и на основе специализированных сопроцессоров или микросхем, которые уже сегодня применяются для добычи в системе Bitcoin.

Если не учитывать процесс добычи, как искусственно созданные сложности, наиболее узким местом с точки зрения производительности в современных блокчейн системах являются базы данных. Если темпы роста количества совершаемых транзакций не снизятся, то, вероятно, уже до конца 2018 года полные цепочки блоков наиболее популярных блокчейн систем перестанут помещаться на один жёсткий диск. В одном из наиболее популярных клиентов системы Ethereum до сих пор нет нормальной поддержки полного узла в режиме «подстриженных» деревьев (pruned mode). В системе Bitcoin такие режимы явным образом не предусмотрены.

При работе с базами данных в блокчейн системах важен не только объём диска, но и его скорость. Уже сейчас в случае размещения данных на обычных жёстких дисках значительная часть времени тратится на чтение и запись данных. Вероятно, уже скоро полные узлы смогут работать только на твердотельных накопителях. В дальнейшем, вероятно, потребуется переход к массивам SSD и использованию более сложных баз данных, обеспечивающих более высокую производительность за счёт параллельной работы с большим числом накопителей.

Что касается технических ограничений, не связанных с базами данных, то наибольшим из них, скорее всего, окажется вычисление хеш-функций. Данная проблема может быть решена за счёт использования видеокарт или других специализированных устройств.

Поэтому многим пользователям, которые сегодня поддерживают полные узлы на своих персональных компьютерах, в скором времени, возможно, придётся отказаться от них в пользу «лёгких» и при этом менее безопасных клиентов. Таким образом, число полных узлов в сети сократится, а размещены они будут, скорее всего, в дата-центрах крупных компаний, которые могут позволить себе высокопроизводительные хранилища данных, сервера с действительно большим количеством оперативной памяти для оптимизации работы баз данных и специализированные ускорители для вычисления хеш-функций. Сумеют ли крупные компании объединиться в общую сеть или же независимо друг от друга будут поддерживать несколько различных систем, и как именно будет организована работа с такими системами, пока непонятно. Однако очевидно, что такие системы будут уже не столь децентрализованы и независимы, как, например, современный Bitcoin.

Возможен и другой подход, заключающийся в распределённом хранении отдельных частей блокчейна на пользовательских устройствах. В этом случае пользователям потребуется значительно меньший объём дискового пространства, однако возрастёт нагрузка на сеть, поскольку большая часть данных будет запрашиваться у других пользователей. Достаточный уровень безопасности при этом может быть достигнут только при значительной избыточности запрашиваемых данных при условии достаточного количества независимых источников. Для организации взаимодействия между узлами, хранящими различные части базы данных могут потребоваться специальные узлы-маршрутизаторы (возможно, такие узлы будут устроены аналогично BitTorrent-треккерам), что также приведёт к снижению децентрализации сети.

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


Оригинал статьи