Язык Move является языком смарт-контрактов, который может работать в блокчейн-среде с реализованной MoveVM. При его создании учитывались многие вопросы безопасности блокчейна и смарт-контрактов, а также были использованы некоторые аспекты проектирования безопасности языка RUST. Какова же безопасность Move как нового поколения языка смарт-контрактов, главным образом ориентированного на безопасность? Может ли он избежать распространенных угроз безопасности, встречающихся в виртуальных машинах контрактов, таких как EVM и WASM, на уровне языка или через связанные механизмы? Существуют ли у него собственные уникальные проблемы безопасности?
В данной статье будет рассмотрена безопасность языка Move с трех аспектов: языковых особенностей, механизмов работы и инструментов верификации.
1. Безопасные характеристики языка Move
Написание корректного кода сложно, и даже после многократного тестирования нельзя гарантировать, что код полностью свободен от уязвимостей. При взаимодействии с недоверенным кодом писать код, который сохраняет ключевые свойства безопасности, еще сложнее. Существует множество технологий, которые могут обеспечить безопасность на время выполнения, такие как песочницы, изоляция процессов, блокировки объектов и другие программные модели; также можно указать статическую безопасность на этапе компиляции, например, используя строгую статическую типизацию или проверки утверждений.
Иногда также можно использовать инструменты семантического анализа и статического анализа, чтобы обеспечить соответствие кода правилам безопасности, даже при взаимодействии с ненадежным кодом, чтобы некоторые доказуемые логические инварианты оставались неизменными.
Эти решения выглядят неплохо, они могут избежать накладных расходов во время выполнения и заранее выявить проблемы с безопасностью. Но, к сожалению, безопасность, достигаемая языками программирования с помощью этих методов, крайне ограничена по двум основным причинам: во-первых, они обычно обладают характеристиками, которые не позволяют использовать инструменты статического анализа, такими как динамическое распределение, совместная изменяемость и отражение, которые нарушают правила инвариантов безопасности, предоставляя хакерам широкие возможности для атак. Во-вторых, большинство языков программирования трудно расширять с использованием статических инструментов, связанных с безопасностью, или выразительных языков с сильной регламентацией. Несмотря на то, что оба этих расширения очень важны, их можно определить заранее.
В отличие от многих существующих языков программирования, язык Move был разработан с учетом поддержки написания программ, которые безопасно взаимодействуют с ненадежным кодом, а также поддерживают статическую проверку. Move обладает такими характеристиками безопасности, потому что отказался от всей нелинейной логики, основанной на гибкости, не поддерживает динамическое распределение и внешние рекурсивные вызовы, а вместо этого использует такие концепции, как обобщения, глобальное хранилище и ресурсы для реализации некоторых альтернативных моделей программирования. Например, Move исключает динамическое распределение и рекурсивные вызовы, которые в других языках смарт-контрактов приводят к дорогостоящим уязвимостям повторного входа.
Чтобы лучше понять особенности языка Move, давайте рассмотрим пример программы:
движение
модуль 0x1::TestCoin {
используйте 0x1::signer;
const ADMIN: address = @0x1;
структура Монета имеет ключ, хранилище {
значение: u64
}
struct Info имеет ключ {
total_supply: u64
}
спецификация модуля {
инвариант для каждого addr: адрес, где существует<coin>(addr):
глобальный<info>(ADMIN).total_supply >= глобальный<coin>0192837465657483939201addr(.value;
}
Публичные развлечения initialize)account: &signer( {
assert!)signer::address_of(account( == ADMIN, 0);
переместить на ) аккаунт, Информация { общее_предложение: 0 } (
}
публичная функция mint)account: &signer, amount: u64(: Информация о получении монеты {
assert!)signer::address_of(account( == ADMIN, 0);
let supply = borrow_global_mut<info>)ADMIN(;
supply.total_supply = supply.total_supply + сумма;
Монета { значение: сумма }
}
Публичные развлечения value)coin: &Coin(: U64 {
coin.value
}
Публичные развлечения value_mut)coin: &mut Coin(: &mut U64 {
&mut coin.value
}
}
a) Модуль)Module(: Каждый модуль Move состоит из серии определений структур и процессов. Модуль может импортировать определения типов и вызывать процессы, объявленные в других модулях. Полное квалифицированное имя модуля начинается с 16-байтового адреса счета, в котором хранится код модуля. Адрес счета служит пространством имен для различия модулей с одинаковыми именами.
b) Структуры): Этот модуль определяет две структуры Coin и Info. Coin представляет токены, распределенные пользователю, а Info фиксирует общее количество токенов. Обе структуры определены как тип ресурсов и могут храниться в постоянном глобальном хранилище ключей/значений.
c( Процесс ) функция ): Код определяет инициализацию, безопасный процесс и небезопасный процесс. Перед созданием Coin необходимо вызвать процесс initialize, чтобы инициализировать значение total_supply в одиночном экземпляре Info на ноль. signer - это специальный тип, представляющий пользователя, проверяемого внешней логикой Move. Утверждение гарантирует, что только указанные учетные записи администратора могут вызывать этот процесс. Процесс mint позволяет администратору создавать новые токены, также с контролем доступа. Процесс value_mut принимает изменяемую ссылку на Coin и возвращает изменяемую ссылку на поле value.
Структура контракта похожа на другие языки смарт-контрактов, но типы ресурсов и глобальное хранилище являются ключевыми механизмами хранения и безопасности ресурсов в языке Move.
Глобальное хранилище позволяет программам Move хранить постоянные данные, которые могут быть прочитаны и записаны программно только модулем, которому они принадлежат, но хранятся в публичном реестре, и пользователи других модулей могут их просматривать. Каждый ключ в глобальном хранилище состоит из полностью квалифицированного имени типа и адреса аккаунта, хранящего значение этого типа. Хотя глобальное хранилище разделяется между всеми модулями, каждый модуль имеет исключительный доступ на чтение и запись к ключам, которые он объявил.
Модуль, объявляющий тип ресурсов, может:
• Опубликуйте значение в глобальном хранилище с помощью команды move_to
• Удалить значение из глобального хранилища с помощью инструкции move_from
• Получите ссылку на значение в глобальном хранилище через инструкцию borrow_global_mut
Модуль может накладывать ограничения на глобальное хранилище, которым он управляет. Например, чтобы гарантировать, что только адрес учетной записи ADMIN может хранить структуры типа Info, это реализуется путем определения процесса initialize, который использует move_to для типа Info и накладывает предварительное условие на вызов move_to по адресу ADMIN.
Вот два механизма статической проверки, которые обеспечивают безопасность кода этого модуля: инвариантные сокращения и проверка байт-кода.
a( Проверка инвариантов ) Проверка условий ): Строка 10 модуля показывает инвариант статической проверки — сумма полей значения всех объектов Coin в системе должна быть равна полю total_value объекта Info, хранящемуся по адресу ADMIN. Инвариант — это термин формальной верификации, обозначающий сохранение состояния. Это свойство сохранения применимо ко всем возможным клиентам модуля.
b( Байт-код валидатор: безопасные типы и линейная структура являются основными областями проверки байт-кода валидатором. Хотя другие модули не могут получить доступ к глобальной ячейке хранения, контролируемой 0x1::TestCoin::Coin, они могут использовать этот тип в своих собственных процессах и объявлениях структур.
Move имеет валидатор байт-кода ), который принудительно применяет типовую систему на уровне байт-кода ), позволяя владельцам модулей предотвращать нежелательные результаты. Только модули, объявляющие структурный тип Coin, могут:
• Создать значение типа Coin
• "Распаковать" значение типа Coin в его компоненты
• Получение ссылки на поле Coin через изменяемую или неизменяемую заимствованность в стиле rust
Валидатор также принудительно устанавливает структуру по умолчанию как линейную, чтобы обеспечить линейную защиту от копирования и уничтожения вне модуля, который объявляет структуру. В то же время валидатор также будет принудительно проверять некоторые распространенные проблемы с памятью для определенных типов.
Процесс проверки в основном делится на три категории:
1( Проверка законности структуры: обеспечение целостности байт-кода, проверка на ошибки незаконных ссылок, дублирующих ресурсных сущностей и незаконные типы подписей и т.д.
2) Семантическая проверка логики процесса: включает в себя ошибки типов параметров, индексы циклов, пустые индексы и повторное определение переменных и т. д.
3) Ошибка при подключении, незаконный вызов внутреннего процесса или несоответствие между декларацией и определением процесса.
Валидатор сначала создает CFG) граф потока управления ), затем проверяет область доступа вызываемого в стеке, гарантируя, что вызываемый контракт не может получить доступ к пространству стека вызывающего. В то же время для проверки типов каждый стек значений поддерживает соответствующий стек типов.
Следующие шаги — это проверка ресурсов и проверка ссылок. Основная проверка ресурсов включает в себя такие ограничения, как отсутствие двойных трат, невозможность уничтожения и обязательная принадлежность. Проверка ссылок сочетает динамический и статический анализ, используя механизм проверки заимствований, аналогичный системе типов Rust.
Наконец, необходимо проверить ссылки, еще раз проверить соответствие объектов ссылок и заявлений, а также контроль доступа к процессу.
( 2. Механизм работы Move
Во-первых, программа Move работает в виртуальной машине и не может получить доступ к системной памяти во время выполнения. Это позволяет Move безопасно работать в ненадежной среде, не поддаваясь разрушению или злоупотреблению.
Во-вторых, программа Move выполняется на стеке. Глобальное хранилище делится на память ) кучу ### и глобальные переменные ( стек ). Память является хранилищем первого уровня, ячейки которого не могут хранить указатели на ячейки памяти. Глобальные переменные используются для хранения указателей на ячейки памяти, но методы индексации различаются. При доступе к глобальным переменным код предоставляет адрес и тип, связанный с этим адресом. Такое разделение упрощает операции, делая семантику языка Move более формализованной.
Инструкции Move выполняются в стековом интерпретаторе. Стековая виртуальная машина проста в реализации и управлении, требует меньше аппаратных ресурсов и подходит для блокчейн-сценариев. В отличие от регистрового интерпретатора, стековый интерпретатор легче контролировать и отслеживать при копировании и перемещении переменных.
В Move значение, определенное как ресурс, может быть уничтожено только разрушительным перемещением (, что делает недействительным место хранения, в котором это значение было сохранено ), но некоторые значения (, такие как целые числа ), могут быть скопированы.
Когда программа Move работает в стеке, ее состояние представлено кортежем ⟨C, M, G, S⟩, который состоит из стека вызовов (C), памяти (M), глобальных переменных (G) и операндов (S). Стек также поддерживает таблицу функций (, сам модуль ) для разбора инструкций, содержащих тело функции.
Стек вызовов содержит всю информацию о контексте выполнения процесса и номера инструкций. При выполнении инструкции Call создается новый объект стека вызовов, параметры вызова сохраняются в памяти и глобальных переменных, после чего интерпретатор выполняет инструкции нового контракта. При встрече с инструкцией ветвления происходит статический переход внутри данного процесса. Процессы внутри модуля зависят от отсутствия циклов, и поскольку в модуле нет динамического назначения, это усиливает неизменность вызовов функций во время выполнения: фрейм вызова процесса procedure обязательно соседний, что предотвращает возможность повторного входа. Вызов return завершает вызов, значение возвращается на вершину стека.
Изучение кода MoveVM показывает, что MoveVM отделяет логику хранения данных и вызова стека (, что является главной отличительной чертой от EVM. В EVM реализация токена ERC20 требует написания логики в одном контракте и записи состояния каждого пользователя, тогда как в MoveVM состояние пользователя ) хранится отдельно в ресурсах под адресом ( аккаунта, при этом вызовы программы должны соответствовать правилам доступа и обязательным правилам относительно ресурсов. Хотя это жертвует некоторой гибкостью, это значительно улучшает безопасность и эффективность выполнения ), что способствует значительному увеличению возможностей параллельного выполнения (.
![Анализ безопасности Move: Игра-перевертыш языка смарт-контрактов])https://img-cdn.gateio.im/webp-social/moments-69101617731b12c40620802eecf76caf.webp(
) 3. Переместить Доказатель
Наконец, давайте познакомимся с вспомогательным инструментом автоматизации аудита Move prover, предоставляемым Move.
Move Prover является инструментом формальной верификации, основанным на логическом выводе. Он использует формальный язык для описания поведения программы и применяет алгоритмы вывода для проверки соответствия программы ожиданиям, помогая разработчикам гарантировать корректность смарт-контрактов и снижать торговые риски. Проще говоря, формальная верификация - это использование математических методов для доказательства отсутствия ошибок в системе.
В настоящее время основные алгоритмы автоматической верификации программного обеспечения основаны на решателе теории удовлетворимости (SMT solver). SMT solver на самом деле является решателем формул. Алгоритмы верификации программного обеспечения верхнего уровня разбивают верификационные цели на формулы, которые передаются решателю SMT для решения, в зависимости от результатов производится дальнейший анализ, и в конечном итоге сообщается о том, выполнена ли верификационная цель или обнаружен контрпример.
Базовый алгоритм верификации — это дедуктивная верификация ###, а также другие алгоритмы верификации, такие как ограниченное моделирование, k-индукция, предикатная абстракция и абстракция путей и т. д.
Move Prover использует алгоритм дедуктивной проверки для верификации того, соответствует ли программа ожиданиям. Это означает, что Move Prover может на основе известных данных делать выводы о поведении программы, обеспечивая его соответствие ожидаемому поведению. Это помогает гарантировать правильность программы и уменьшает объем ручного тестирования.
Общая архитектура Move Prover следующая:
Сначала Move Prover получает файл Move с спецификацией входных данных программы (specification). Move Parser извлекает спецификацию из исходного кода. Move компилятор компилирует исходный файл в байт-код, который вместе со спецификацией преобразует в модель объектов проверяющего (Prover Object Model).
Модель переведена на промежуточный язык Boogie. Код Boogie передается в систему верификации Boogie для "генерации условий верификации". Условия верификации передаются в решатель Z3 (, разработанный Microsoft, SMT-решатель ).
После передачи VC в Z3, проверка SMT формулы ( программы осуществляется для определения, соответствует ли она спецификации ) и является ли она невыполнимой. Если да, это означает, что спецификация верна. В противном случае генерируется модель, удовлетворяющая условиям, которая преобразуется обратно в формат Boogie для выпуска диагностического отчета. Диагностический отчет восстанавливается в виде ошибок на уровне исходного кода, аналогичных стандартным ошибкам компилятора.
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
17 Лайков
Награда
17
5
Репост
Поделиться
комментарий
0/400
SchrodingerAirdrop
· 08-09 21:11
move еще не достаточно безопасен, поверьте мне
Посмотреть ОригиналОтветить0
DataBartender
· 08-07 02:38
Снова раздувают move до небес.
Посмотреть ОригиналОтветить0
AirdropHarvester
· 08-07 02:29
Move? Слышится, как проблема, так же сложно учить, как Rust.
Посмотреть ОригиналОтветить0
MoneyBurner
· 08-07 02:28
Снова хочешь обмануть меня и заставить войти в позицию, чтобы посмотреть новую публичную цепочку. В прошлый раз я так потерял.
Посмотреть ОригиналОтветить0
StableNomad
· 08-07 02:28
хмм, еще один "безопасный" язык... честно говоря, напоминает мне солану в 2021 году
Глубина безопасности языка Move: особенности языка, механизмы работы и автоматизированный аудит
Введение
Язык Move является языком смарт-контрактов, который может работать в блокчейн-среде с реализованной MoveVM. При его создании учитывались многие вопросы безопасности блокчейна и смарт-контрактов, а также были использованы некоторые аспекты проектирования безопасности языка RUST. Какова же безопасность Move как нового поколения языка смарт-контрактов, главным образом ориентированного на безопасность? Может ли он избежать распространенных угроз безопасности, встречающихся в виртуальных машинах контрактов, таких как EVM и WASM, на уровне языка или через связанные механизмы? Существуют ли у него собственные уникальные проблемы безопасности?
В данной статье будет рассмотрена безопасность языка Move с трех аспектов: языковых особенностей, механизмов работы и инструментов верификации.
1. Безопасные характеристики языка Move
Написание корректного кода сложно, и даже после многократного тестирования нельзя гарантировать, что код полностью свободен от уязвимостей. При взаимодействии с недоверенным кодом писать код, который сохраняет ключевые свойства безопасности, еще сложнее. Существует множество технологий, которые могут обеспечить безопасность на время выполнения, такие как песочницы, изоляция процессов, блокировки объектов и другие программные модели; также можно указать статическую безопасность на этапе компиляции, например, используя строгую статическую типизацию или проверки утверждений.
Иногда также можно использовать инструменты семантического анализа и статического анализа, чтобы обеспечить соответствие кода правилам безопасности, даже при взаимодействии с ненадежным кодом, чтобы некоторые доказуемые логические инварианты оставались неизменными.
Эти решения выглядят неплохо, они могут избежать накладных расходов во время выполнения и заранее выявить проблемы с безопасностью. Но, к сожалению, безопасность, достигаемая языками программирования с помощью этих методов, крайне ограничена по двум основным причинам: во-первых, они обычно обладают характеристиками, которые не позволяют использовать инструменты статического анализа, такими как динамическое распределение, совместная изменяемость и отражение, которые нарушают правила инвариантов безопасности, предоставляя хакерам широкие возможности для атак. Во-вторых, большинство языков программирования трудно расширять с использованием статических инструментов, связанных с безопасностью, или выразительных языков с сильной регламентацией. Несмотря на то, что оба этих расширения очень важны, их можно определить заранее.
В отличие от многих существующих языков программирования, язык Move был разработан с учетом поддержки написания программ, которые безопасно взаимодействуют с ненадежным кодом, а также поддерживают статическую проверку. Move обладает такими характеристиками безопасности, потому что отказался от всей нелинейной логики, основанной на гибкости, не поддерживает динамическое распределение и внешние рекурсивные вызовы, а вместо этого использует такие концепции, как обобщения, глобальное хранилище и ресурсы для реализации некоторых альтернативных моделей программирования. Например, Move исключает динамическое распределение и рекурсивные вызовы, которые в других языках смарт-контрактов приводят к дорогостоящим уязвимостям повторного входа.
Чтобы лучше понять особенности языка Move, давайте рассмотрим пример программы:
движение модуль 0x1::TestCoin { используйте 0x1::signer;
}
a) Модуль)Module(: Каждый модуль Move состоит из серии определений структур и процессов. Модуль может импортировать определения типов и вызывать процессы, объявленные в других модулях. Полное квалифицированное имя модуля начинается с 16-байтового адреса счета, в котором хранится код модуля. Адрес счета служит пространством имен для различия модулей с одинаковыми именами.
b) Структуры): Этот модуль определяет две структуры Coin и Info. Coin представляет токены, распределенные пользователю, а Info фиксирует общее количество токенов. Обе структуры определены как тип ресурсов и могут храниться в постоянном глобальном хранилище ключей/значений.
c( Процесс ) функция ): Код определяет инициализацию, безопасный процесс и небезопасный процесс. Перед созданием Coin необходимо вызвать процесс initialize, чтобы инициализировать значение total_supply в одиночном экземпляре Info на ноль. signer - это специальный тип, представляющий пользователя, проверяемого внешней логикой Move. Утверждение гарантирует, что только указанные учетные записи администратора могут вызывать этот процесс. Процесс mint позволяет администратору создавать новые токены, также с контролем доступа. Процесс value_mut принимает изменяемую ссылку на Coin и возвращает изменяемую ссылку на поле value.
Структура контракта похожа на другие языки смарт-контрактов, но типы ресурсов и глобальное хранилище являются ключевыми механизмами хранения и безопасности ресурсов в языке Move.
Глобальное хранилище позволяет программам Move хранить постоянные данные, которые могут быть прочитаны и записаны программно только модулем, которому они принадлежат, но хранятся в публичном реестре, и пользователи других модулей могут их просматривать. Каждый ключ в глобальном хранилище состоит из полностью квалифицированного имени типа и адреса аккаунта, хранящего значение этого типа. Хотя глобальное хранилище разделяется между всеми модулями, каждый модуль имеет исключительный доступ на чтение и запись к ключам, которые он объявил.
Модуль, объявляющий тип ресурсов, может: • Опубликуйте значение в глобальном хранилище с помощью команды move_to • Удалить значение из глобального хранилища с помощью инструкции move_from • Получите ссылку на значение в глобальном хранилище через инструкцию borrow_global_mut
Модуль может накладывать ограничения на глобальное хранилище, которым он управляет. Например, чтобы гарантировать, что только адрес учетной записи ADMIN может хранить структуры типа Info, это реализуется путем определения процесса initialize, который использует move_to для типа Info и накладывает предварительное условие на вызов move_to по адресу ADMIN.
Вот два механизма статической проверки, которые обеспечивают безопасность кода этого модуля: инвариантные сокращения и проверка байт-кода.
a( Проверка инвариантов ) Проверка условий ): Строка 10 модуля показывает инвариант статической проверки — сумма полей значения всех объектов Coin в системе должна быть равна полю total_value объекта Info, хранящемуся по адресу ADMIN. Инвариант — это термин формальной верификации, обозначающий сохранение состояния. Это свойство сохранения применимо ко всем возможным клиентам модуля.
b( Байт-код валидатор: безопасные типы и линейная структура являются основными областями проверки байт-кода валидатором. Хотя другие модули не могут получить доступ к глобальной ячейке хранения, контролируемой 0x1::TestCoin::Coin, они могут использовать этот тип в своих собственных процессах и объявлениях структур.
Move имеет валидатор байт-кода ), который принудительно применяет типовую систему на уровне байт-кода ), позволяя владельцам модулей предотвращать нежелательные результаты. Только модули, объявляющие структурный тип Coin, могут: • Создать значение типа Coin • "Распаковать" значение типа Coin в его компоненты • Получение ссылки на поле Coin через изменяемую или неизменяемую заимствованность в стиле rust
Валидатор также принудительно устанавливает структуру по умолчанию как линейную, чтобы обеспечить линейную защиту от копирования и уничтожения вне модуля, который объявляет структуру. В то же время валидатор также будет принудительно проверять некоторые распространенные проблемы с памятью для определенных типов.
Процесс проверки в основном делится на три категории: 1( Проверка законности структуры: обеспечение целостности байт-кода, проверка на ошибки незаконных ссылок, дублирующих ресурсных сущностей и незаконные типы подписей и т.д. 2) Семантическая проверка логики процесса: включает в себя ошибки типов параметров, индексы циклов, пустые индексы и повторное определение переменных и т. д. 3) Ошибка при подключении, незаконный вызов внутреннего процесса или несоответствие между декларацией и определением процесса.
Валидатор сначала создает CFG) граф потока управления ), затем проверяет область доступа вызываемого в стеке, гарантируя, что вызываемый контракт не может получить доступ к пространству стека вызывающего. В то же время для проверки типов каждый стек значений поддерживает соответствующий стек типов.
Следующие шаги — это проверка ресурсов и проверка ссылок. Основная проверка ресурсов включает в себя такие ограничения, как отсутствие двойных трат, невозможность уничтожения и обязательная принадлежность. Проверка ссылок сочетает динамический и статический анализ, используя механизм проверки заимствований, аналогичный системе типов Rust.
Наконец, необходимо проверить ссылки, еще раз проверить соответствие объектов ссылок и заявлений, а также контроль доступа к процессу.
( 2. Механизм работы Move
Во-первых, программа Move работает в виртуальной машине и не может получить доступ к системной памяти во время выполнения. Это позволяет Move безопасно работать в ненадежной среде, не поддаваясь разрушению или злоупотреблению.
Во-вторых, программа Move выполняется на стеке. Глобальное хранилище делится на память ) кучу ### и глобальные переменные ( стек ). Память является хранилищем первого уровня, ячейки которого не могут хранить указатели на ячейки памяти. Глобальные переменные используются для хранения указателей на ячейки памяти, но методы индексации различаются. При доступе к глобальным переменным код предоставляет адрес и тип, связанный с этим адресом. Такое разделение упрощает операции, делая семантику языка Move более формализованной.
Инструкции Move выполняются в стековом интерпретаторе. Стековая виртуальная машина проста в реализации и управлении, требует меньше аппаратных ресурсов и подходит для блокчейн-сценариев. В отличие от регистрового интерпретатора, стековый интерпретатор легче контролировать и отслеживать при копировании и перемещении переменных.
В Move значение, определенное как ресурс, может быть уничтожено только разрушительным перемещением (, что делает недействительным место хранения, в котором это значение было сохранено ), но некоторые значения (, такие как целые числа ), могут быть скопированы.
Когда программа Move работает в стеке, ее состояние представлено кортежем ⟨C, M, G, S⟩, который состоит из стека вызовов (C), памяти (M), глобальных переменных (G) и операндов (S). Стек также поддерживает таблицу функций (, сам модуль ) для разбора инструкций, содержащих тело функции.
Стек вызовов содержит всю информацию о контексте выполнения процесса и номера инструкций. При выполнении инструкции Call создается новый объект стека вызовов, параметры вызова сохраняются в памяти и глобальных переменных, после чего интерпретатор выполняет инструкции нового контракта. При встрече с инструкцией ветвления происходит статический переход внутри данного процесса. Процессы внутри модуля зависят от отсутствия циклов, и поскольку в модуле нет динамического назначения, это усиливает неизменность вызовов функций во время выполнения: фрейм вызова процесса procedure обязательно соседний, что предотвращает возможность повторного входа. Вызов return завершает вызов, значение возвращается на вершину стека.
Изучение кода MoveVM показывает, что MoveVM отделяет логику хранения данных и вызова стека (, что является главной отличительной чертой от EVM. В EVM реализация токена ERC20 требует написания логики в одном контракте и записи состояния каждого пользователя, тогда как в MoveVM состояние пользователя ) хранится отдельно в ресурсах под адресом ( аккаунта, при этом вызовы программы должны соответствовать правилам доступа и обязательным правилам относительно ресурсов. Хотя это жертвует некоторой гибкостью, это значительно улучшает безопасность и эффективность выполнения ), что способствует значительному увеличению возможностей параллельного выполнения (.
![Анализ безопасности Move: Игра-перевертыш языка смарт-контрактов])https://img-cdn.gateio.im/webp-social/moments-69101617731b12c40620802eecf76caf.webp(
) 3. Переместить Доказатель
Наконец, давайте познакомимся с вспомогательным инструментом автоматизации аудита Move prover, предоставляемым Move.
Move Prover является инструментом формальной верификации, основанным на логическом выводе. Он использует формальный язык для описания поведения программы и применяет алгоритмы вывода для проверки соответствия программы ожиданиям, помогая разработчикам гарантировать корректность смарт-контрактов и снижать торговые риски. Проще говоря, формальная верификация - это использование математических методов для доказательства отсутствия ошибок в системе.
В настоящее время основные алгоритмы автоматической верификации программного обеспечения основаны на решателе теории удовлетворимости (SMT solver). SMT solver на самом деле является решателем формул. Алгоритмы верификации программного обеспечения верхнего уровня разбивают верификационные цели на формулы, которые передаются решателю SMT для решения, в зависимости от результатов производится дальнейший анализ, и в конечном итоге сообщается о том, выполнена ли верификационная цель или обнаружен контрпример.
Базовый алгоритм верификации — это дедуктивная верификация ###, а также другие алгоритмы верификации, такие как ограниченное моделирование, k-индукция, предикатная абстракция и абстракция путей и т. д.
Move Prover использует алгоритм дедуктивной проверки для верификации того, соответствует ли программа ожиданиям. Это означает, что Move Prover может на основе известных данных делать выводы о поведении программы, обеспечивая его соответствие ожидаемому поведению. Это помогает гарантировать правильность программы и уменьшает объем ручного тестирования.
Общая архитектура Move Prover следующая:
Сначала Move Prover получает файл Move с спецификацией входных данных программы (specification). Move Parser извлекает спецификацию из исходного кода. Move компилятор компилирует исходный файл в байт-код, который вместе со спецификацией преобразует в модель объектов проверяющего (Prover Object Model).
Модель переведена на промежуточный язык Boogie. Код Boogie передается в систему верификации Boogie для "генерации условий верификации". Условия верификации передаются в решатель Z3 (, разработанный Microsoft, SMT-решатель ).
После передачи VC в Z3, проверка SMT формулы ( программы осуществляется для определения, соответствует ли она спецификации ) и является ли она невыполнимой. Если да, это означает, что спецификация верна. В противном случае генерируется модель, удовлетворяющая условиям, которая преобразуется обратно в формат Boogie для выпуска диагностического отчета. Диагностический отчет восстанавливается в виде ошибок на уровне исходного кода, аналогичных стандартным ошибкам компилятора.
! [MoveAnn.]