Суть параллельности заключается в повышении эффективности выполнения слоя путем многопутевого выполнения, и для реализации многопутевого выполнения блокчейн должен выполнить ряд действий, таких как обнаружение конфликтов и механизмы отката, чтобы обеспечить их параллельное выполнение без ущерба для окончательной согласованности состояния, и в некоторой степени улучшить базу данных.
Автор: Tia, Techub News
Блокчейн жертвует эффективностью из-за своей децентрализованной конструкции, поэтому повышение скорости выполнения всегда было одной из насущных проблем. «Исполнительный уровень» блокчейна - это ключевая часть, обрабатывающая каждую транзакцию и добавляющая ее в цепь. Для ускорения обработки повышение на уровне выполнения стало одной из ключевых стратегий, и параллельное выполнение является важным прорывом в этой области.
Традиционные блокчейны обычно обрабатывают транзакции последовательно, что значительно ограничивает скорость транзакций, особенно в сетях с высокой плотностью транзакций, что приводит к перегрузке. Однако через параллельное выполнение несколько транзакций можно обрабатывать одновременно, значительно повышая эффективность выполнения и снижая нагрузку на сеть.
Чтобы лучше понять, что такое параллельность, мы сначала введем выполнение и используем Ethereum в режиме PBS после Merge в качестве примера, чтобы объяснить, что такое выполнение, одновременно показывая место выполнения в жизненном цикле транзакции.
Конкретные этапы выполнения транзакции
Транзакция поступает в пул памяти и проходит отбор и сортировку: это предварительный этап после подачи транзакции, включающий взаимодействие Mempool, Поисковика и Строителя для завершения отбора и сортировки транзакций.
Строитель создает блок (но не выполняет): Строитель упорядочивает прибыльные транзакции в блок для завершения упаковки и сортировки транзакций.
Предложитель проверяет и отправляет блок: После завершения сборки блока Строитель отправляет предложение блока Предложителю. Предложитель проверяет структуру блока и содержимое транзакции, а затем официально отправляет блок в сеть для начала выполнения.
Выполнение транзакции: После подачи блока узлы последовательно выполняют транзакции внутри блока. Это ключевая стадия обновления состояния, каждая транзакция вызывает вызов смарт-контракта, изменение баланса аккаунта или изменение состояния.
Свидетели подтверждают: валидаторы подтверждают результаты выполнения блока и корень состояния, и это служит окончательным подтверждением. Это обеспечивает подлинность и действительность блока на уровне выполнения и предотвращает несоответствия.
Синхронизация состояния: Каждый узел синхронизирует результаты выполнения блока (например, обновления баланса аккаунта, состояния контракта и т. д.) в своем локальном состоянии, после выполнения каждой транзакции узел вычисляет и хранит новый корень состояния для использования в следующем блоке в качестве начального состояния.
Конечно, это всего лишь синхронизация состояния транзакций на уровне блоков. Чтобы поддерживать актуальное состояние на цепи, узлы обычно синхронизируют данные по блокам и продолжают проверять блоки и состояния. Но для достижения окончательности в механизме POS агрегатору необходимо объединить подписи свидетелей в каждом слоте в одну полную подпись и передать ее Предложителю следующего слота. А валидаторам потребуется по истечении одного эпохи на основе количества голосов подтвердить состояние всех блоков в этом эпохе, формируя временный контрольный пункт состояния консенсуса. Когда два последовательных эпох получают поддержку большинства валидаторов, блоки и транзакции достигают окончательности.
С точки зрения всего жизненного цикла транзакции выполнение происходит после того, как Предложитель проверяет структуру блока и содержимое транзакции, отправленные Строителем. Фактический процесс выполнения требует обработки транзакций по одной и обновления соответствующего состояния аккаунтов или контрактов. После выполнения всех транзакций Предложитель вычисляет новый корень состояния (меркелев корень), который является сводкой результатов выполнения всех транзакций текущего блока и конечного глобального состояния. Проще говоря, полный процесс выполнения блока включает в себя серию вычислений, необходимых для изменения Ethereum из предыдущего состояния в следующее состояние, от выполнения каждой транзакции до вычисления меркелевого корня.
Последовательное выполнение
Противоположностью параллельному выполнению является последовательное выполнение, то есть общий способ выполнения в блокчейнах. Обычно транзакции выполняются последовательно по порядку. Когда транзакция выполнена, Ethereum обновляет состояние аккаунта и связанную информацию (например, баланс, данные хранилища контракта) в дереве состояния аккаунта, создается новый хеш состояния аккаунта. После завершения обновления всех деревьев состояния аккаунтов формируется корневой узел хеша дерева состояния, который называется состоянием меркелевого корня. После завершения меркелевых корней состояния, транзакции и квитанций, заголовок блока проходит хеширование, чтобы сгенерировать хеш данного блока.
И в этом контексте порядок выполнения транзакций имеет решающее значение. Поскольку меркелево дерево представляет собой бинарное дерево хешей, разные последовательности формируют разные значения меркелевого корня.
Параллельное выполнение
В условиях параллельного выполнения узлы пытаются обрабатывать транзакции в блоке параллельно. Они не выполняются последовательно по одной транзакции, а распределяются по различным «исполнительным путям», чтобы они могли выполняться одновременно. Путем параллельного выполнения система может более эффективно обрабатывать транзакции в блоке, увеличивая пропускную способность.
После выполнения всех транзакций узлы собирают результаты выполнения (т.е. обновления состояния, затронутые транзакциями) и формируют новое состояние блока. Это состояние будет добавлено в блокчейн, представляя собой последнее глобальное состояние на цепи.
Конфликт состояния
Поскольку параллельное выполнение обрабатывает транзакции по разным путям одновременно, одной из основных проблем параллельного выполнения является конфликт состояния. То есть может происходить несколько транзакций, которые одновременно читают или записывают данные (состояние) на блокчейне в одном и том же временном интервале. Если с этим не справиться должным образом, это может привести к неопределенности результата выполнения. Порядок обновления состояния различен, и в конечном итоге результаты вычислений также будут разными. Например,
Предположим, что есть две транзакции, транзакция A и транзакция B, которые обе пытаются обновить баланс одного и того же аккаунта:
Торговля A: Увеличить баланс аккаунта на 10.
Торговля B: Увеличить баланс аккаунта на 20.
Начальный баланс аккаунта составляет 100.
Если мы выполняем последовательно, результат выполнения в определенном порядке будет определенным:
1. Сначала выполнить транзакцию A, затем транзакцию B:
Баланс аккаунта сначала увеличивается на 10, становится 110.
Затем увеличивается на 20, в конечном итоге становится 130.
2. Сначала выполнить транзакцию B, затем транзакцию A:
Баланс аккаунта сначала увеличивается на 20, становится 120.
Затем увеличивается на 10, в конечном итоге становится 130.
В обоих этих порядка конечный баланс составляет 130, поскольку система гарантирует согласованность порядка выполнения транзакций.
Но в среде параллельного выполнения транзакции A и B могут одновременно считывать начальный баланс 100 и выполнять свои вычисления:
Торговля A считывает баланс 100, после вычислений обновляет баланс до 110.
Торговля B также считывает баланс 100, после вычислений обновляет баланс до 120.
В этом случае, поскольку транзакции выполняются одновременно, конечный баланс обновляется только до 120, а не до 130, поскольку операции транзакций A и B «перекрыли» результаты друг друга, что и привело к конфликту состояния.
Проблемы с конфликтами состояния обычно называются «перекрытием данных», что означает, что когда транзакции пытаются одновременно изменить одни и те же данные, они могут перекрывать результаты вычислений друг друга, что приводит к неправильному конечному состоянию. Другой тип проблемы конфликта состояния может возникнуть из-за невозможности гарантировать порядок выполнения. Поскольку несколько транзакций завершают операции в разные временные интервалы, это может приводить к различным порядкам выполнения. Разные порядки могут приводить к различным результатам вычислений, делая результаты неопределенными.
Чтобы избежать этой неопределенности, системы параллельного выполнения блокчейна обычно вводят некоторые механизмы обнаружения конфликтов и отката или заранее проводят анализ зависимости транзакций, чтобы обеспечить их параллельное выполнение без ущерба для окончательной согласованности состояния.
Оптимистичное параллельное выполнение и детерминированная параллельность
Существует два способа решения проблемы возможных конфликтов состояния: детерминированная параллельность и оптимистичное параллельное выполнение. Эти два режима имеют свои компромиссы в эффективности и сложности дизайна.
Детерминированная параллельность требует заранее заявить о доступе к состоянию, валидатор или последователь проверяет заявленный доступ к состоянию во время сортировки транзакций. Если несколько транзакций пытаются записать одно и то же состояние, они будут помечены как конфликтные и не будут выполнены одновременно. Конкретные реализации различных цепей могут различаться в форме предварительного заявления о доступе к состоянию, но обычно включают следующие способы:
Через ограничения, установленные контрактами: разработчики непосредственно определяют диапазон доступа к состоянию в смарт-контракте. Например, перевод токенов ERC-20 требует доступа к полям баланса отправителя и получателя.
Через структурированные данные транзакции: добавьте специальные поля в транзакцию, чтобы пометить доступ к состоянию.
Через анализ компилятора: компиляторы высокоуровневых языков могут статически анализировать код контракта и автоматически генерировать наборы доступа к состоянию.
Через обязательные декларации фрейма: некоторые фреймы требуют, чтобы разработчики явно указывали необходимые доступы к состоянию при вызове функций.
Оптимистичное параллельное выполнение предполагает предварительную обработку транзакций, а при возникновении конфликта снова последовательно выполнять затронутые транзакции. Чтобы избежать конфликтов, основная идея оптимистичного параллельного выполнения заключается в быстром предположении и оценке состояния с использованием исторических данных и статического анализа. Система, не проверяя полностью, предполагает, что некоторые операции или обновления состояния действительны, стараясь избежать ожидания всех процессов верификации, тем самым повышая производительность и пропускную способность.
Хотя оптимистичное параллельное выполнение может избегать конфликтов через быструю оценку и предположения о состоянии, все же существуют некоторые неизбежные проблемы, особенно в отношении выполнения контрактов или кросс-чейн транзакций. Если конфликты происходят часто, повторное выполнение может значительно замедлить производительность системы и увеличить потребление вычислительных ресурсов.
Детерминированная параллельность предотвращает конфликты, которые могут возникнуть с оптимистичной параллельностью, путем проверки зависимостей состояния перед транзакцией, но поскольку требуется точно заявить о зависимостях состояния перед подачей транзакции, это ставит перед разработчиками более высокие требования, что увеличивает сложность реализации.
Проблема параллельности EVM
Отношение к конфликту состояния может быть определенным и оптимистичным, при реализации параллельного выполнения также необходимо учитывать архитектуру базы данных блокчейна. Проблема конфликтов состояния в параллельном выполнении особенно сложна в EVM под архитектурой меркелевого дерева. Меркелево дерево - это иерархическая хэш-структура, и каждый раз, когда транзакция изменяет определенные данные состояния, корневой хэш меркелевого дерева также необходимо обновить. Этот процесс обновления рекурсивен, начиная с листовых узлов и постепенно поднимаясь к корневому узлу. Поскольку хэш является необратимым, то вычислить верхний уровень можно только после завершения изменений в нижнем уровне, эта особенность делает параллельное обновление очень сложным.
Если две транзакции выполняются параллельно и обращаются к одному и тому же состоянию (например, к балансу аккаунта), это может привести к конфликту узлов меркелевого дерева. Решение такого конфликта обычно требует дополнительных механизмов управления транзакциями, чтобы обеспечить一致ность корневого хеш-значения для нескольких ветвей. Это не легко реализовать для EVM, поскольку требуется компромисс между параллелизацией и согласованностью состояния.
Непараллельные решения EVM
Solana
В отличие от глобального дерева состояния Ethereum, Solana использует модель аккаунтов. Каждый аккаунт - это независимое хранилище, хранящееся в бухгалтерской книге, что позволяет избежать проблемы конфликтов путей.
Solana - это детерминированная параллельность. В Solana каждая транзакция должна явно указывать при подаче, к каким аккаунтам и каким разрешениям (только для чтения или чтения и записи) она будет обращаться. Такой дизайн позволяет узлам блокчейна заранее анализировать ресурсы, к которым требуется доступ, еще до выполнения транзакций. Поскольку все зависимости аккаунтов уже были четко заявлены до начала выполнения транзакций, узлы могут определить, какие транзакции будут обращаться к одним и тем же аккаунтам, а какие транзакции могут безопасно выполняться параллельно, что позволяет реализовать интеллектуальное распределение, избегая конфликтов и создавая основу для параллельного планирования.
Поскольку каждая транзакция заранее заявляет о необходимых доступах к аккаунтам и разрешениях перед выполнением, Solana может проверять, есть ли зависимость аккаунтов между транзакциями (модель Sealevel). Если между транзакциями нет общих читаемых и записываемых аккаунтов, система может распределить их на разные процессоры для параллельного выполнения.
Aptos
Дизайн параллельного выполнения Aptos значительно отличается от Ethereum, он включает в себя некоторые ключевые инновации в архитектуре и механизмах, в основном в модели аккаунтов и хранении состояния.
В Ethereum выполнение транзакций требует частого обновления глобального дерева состояния (MPT). Состояние всех аккаунтов и контрактов хранится в общем дереве состояния, и любая транзакция должна получать доступ и обновлять часть этого дерева состояния. В отличие от этого, Aptos разделяет аккаунты на независимые единицы состояния, где каждый объект является независимой парой ключ-значение, объекты могут существовать независимо друг от друга и связываться только при явной ссылке. Между объектами нет общих путей в дереве, нет гонки за блокировку, и их можно полностью выполнять параллельно.
Основная структура данных Aptos - это Jellyfish Merkle Tree. Состояние каждого объекта в конечном итоге хранится в JMT в виде независимой пары ключ-значение. В отличие от MPT Ethereum, Jellyfish Merkle Tree имеет структуру полных бинарных деревьев, что упрощает путь хранения и запросы к узлам, значительно снижая время проверки. Кроме того, положение каждого аккаунта в дереве фиксировано, и узлы в дереве хранятся независимо, что позволяет обновлениям и поиску нескольких аккаунтов выполняться параллельно.
Aptos - это оптимистичное параллельное выполнение, которое не требует заранее предоставлять все зависимости заявленных аккаунтов. Для этого Aptos использует Block-STM, который использует предустановленный порядок транзакций для оценки зависимости, тем самым уменьшая количество прерываний.
Параллельный EVM
По сравнению с параллельностью, не основанной на EVM, EVM параллельность сталкивается с большими техническими трудностями при обработке зависимостей состояния, обнаружении конфликтов, управлении Gas и механизмами отката. Чтобы лучше понять это, мы можем обратиться к тому, как некоторые проекты параллельного EVM (такие как Sui, Monad, Canto) решают эти проблемы.
Sui
Sui, как и Aptos, также использует объектную модель для обработки состояния, принимая каждый объект (например, состояние аккаунта, умного контракта) за независимый ресурс, которые различаются по уникальному идентификатору объекта. Когда транзакции касаются разных объектов, эти транзакции могут обрабатываться параллельно, так как они работают с различными состояниями и не создают прямых конфликтов.
Хотя Sui использует объектную модель для управления состоянием, архитектура Sui совместима с EVM через дополнительный адаптационный слой или абстрактный механизм, чтобы связать объектную модель и модель аккаунтов EVM.
В Sui планирование транзакций использует стратегию оптимистичного параллельного выполнения, предполагая, что между транзакциями нет конфликтов. Если конфликт происходит, система использует механизм отката для восстановления состояния.
Sui использует объектную модель и технологии изоляции состояния, что эффективно предотвращает проблемы зависимости состояния. Каждый объект является независимым ресурсом, различные транзакции могут выполняться параллельно, что повышает пропускную способность и эффективность. Однако такой подход имеет свои недостатки, такие как сложность объектной модели и накладные расходы на механизм отката. Если между транзакциями возникает конфликт, необходимо откатить часть состояния, что увеличивает нагрузку на систему и может повлиять на эффективность параллельной обработки. По сравнению с параллельными системами, не основанными на EVM (такими как Solana), Sui требует больше вычислительных и ресурсных затрат для поддержания эффективной параллельности.
Monad
Как и Sui, Monad также использует оптимистичное параллельное выполнение. Однако оптимистичное выполнение Monad перед фактическим выполнением транзакций будет предсказывать некоторые зависимые транзакции, и предсказание в основном осуществляется с помощью статического анализатора кода Monad. Для предсказания необходимо получить доступ к состоянию, а способ хранения состояния в базе данных Ethereum делает это очень сложным. Чтобы сделать процесс чтения состояния более эффективным, Monad также реконструировала базу данных.
Дерево состояния Monad делится на разделы, каждый из которых поддерживает свое собственное состояние поддерева. При обновлении необходимо изменить только соответствующий сегмент, не перестраивая все дерево состояния. Используя таблицу индексов состояния, можно быстро находить состояние в разделе, уменьшая взаимодействие между разделами.
Резюме
Суть параллельности заключается в повышении эффективности выполнения слоя путем многопутевого выполнения, и для реализации многопутевого выполнения блокчейн должен выполнить ряд действий, таких как обнаружение конфликтов и механизмы отката, чтобы обеспечить их параллельное выполнение без ущерба для окончательной согласованности состояния, и в некоторой степени улучшить базу данных.
Конечно, повышение эффективности исполнительного уровня не ограничивается только параллельным выполнением; оптимизация на этапе выполнения также может быть достигнута путем снижения операций чтения/записи, необходимых для одной транзакции в базе данных. Однако увеличение скорости всей цепи охватывает более широкий спектр аспектов, включая повышение эффективности уровня консенсуса.
Каждая технология имеет свои специфические ограничения. Параллельность - это всего лишь один из способов повышения эффективности, и в конечном итоге решение о том, использовать эту технологию или нет, должно учитывать, насколько она дружелюбна к разработчикам и сможет ли она быть реализована без жертвования децентрализацией, и так далее. Стек технологий не всегда лучше, чем больше, и, по крайней мере, для Ethereum параллельность не так привлекательна, если рассматривать только с точки зрения повышения эффективности, добавление параллельности для Ethereum не является оптимальным решением, будь то с точки зрения простоты или с точки зрения текущей дорожной карты Ethereum, сосредоточенной на Rollup.