Ramil 🔵 pfp
Ramil 🔵

@ramilmust

Тесты? Тесты. Часть 1 Вернемся к теории, точнее к общим положениям Одна из задач в приватном аудите (что это такое писал здесь (https://t.me/web3securityresearch/8)) - оценка зрелости кодовой базы Важная часть этого параметра - покрытие тестами и использование специальных инструментов командой разработчиков Тестирование мне нравится воспринимать как послойную защиту, чем больше слоев, тем меньше шансов пропустить критическую уязвимость 1 слой. Unit тесты Что делают: здесь всё как в "обычном" программировании. У нас есть функция, мы передаем ей фиксированные параметры, чтобы проверить работает ли она ожидаемым образом с нормальными данными, с краевыми случаями, с неправильными данными. Это база, это обязательно должно быть с хорошим процентом покрытия кода Как внедрять: - Hardhat использует этого Mocha/Chai, на JS, с 2025 есть поддержка тестов на Solidity - Foundry имеет встроенные инструменты с использованием cheatcodes (оч крутая штука, достойна поста), на Solidity 2 слой. Stateless Fuzz тесты Что делают: по сути это unit тесты на стероидах. Специальный фаззер автоматически генерирует входные данные на экземпляр функции. Тысячи генераций, каждый раз новый экземпляр, поэтому и stateless, то есть без сохранения состояния. Тоже можно считать базой, пишутся достаточно просто, можно сделать из unit Как внедрять: - Hardhat можно использовать специализированный fuzzer Echidna (https://github.com/crytic/echidna), но с 2025 года имеет встроенный fuzzer - Foundry имеет встроенный fuzzer 3 слой. Мок тесты Что делают: Мок-тесты позволяют имитировать поведение внешних зависимостей, таких как другие контракты, оракулы или внешние вызовы, без их реального развертывания. По сути, это расширение unit-тестов для симуляции реального мира Как внедрять: - Hardhat: библиотека Smock для создания моков контрактов, или пишите на solidity (круто они обновились в 2025, да) - Foundry: Встроенные cheatcodes, такие как mockCall, expectCall или prank для имитации вызовов и отправителей 4 слой. Интеграционные тесты Что делают: проверяют, как несколько контрактов взаимодействуют друг с другом в полной системе, симулируя реальные сценарии. В отличие от unit или mok, здесь учитываются реальные зависимости, газовые затраты, события и состояние сети Как внедрять: - Hardhat: hardhat-network для forking mainnet (npx hardhat node --fork), развертывайте контракты и пишите тесты на JS/TS с Mocha/Chai или на Solidity - Foundry: использовать читкод vm.createFork для симуляции реальной сети, cheatcodes для манипуляции состоянием и развертывание нескольких контрактов 5 слой. Статические анализаторы Что делают: в отличие от предыдущих "слоев", статические анализаторы не запускают код, они исследуют его на присутствие паттернов, соответствующих потенциальным уязвимостям, нарушению лучших практик и стандартов. Легко запускаются, но выдачу надо внимательно анализировать Как внедрять: - Статических анализаторов несколько, например Slither, Aderyn, Mythril. Я использовал первые два, запускаются в терминале, генерируют отчеты, находят немного разно 6 слой. Stateful Fuzz тесты/Тесты инварианта Инвариант - это состояние/поведение вашего контракта, которое не должно нарушаться ни при каких обстоятельствах. Из-за того, что само слово invariant несколько перегружено смыслами, то получается, что так называют и это нерушимое правило и способ тестирования. Отличие от stateless в том, что в этом случае генерируемые фаззером значения отправляются на один и тот же экземпляр/экземпляры контракта/функций. Из-за этого его сложнее написать, это тоже достойно отдельного поста. Суть там следующая, если не зарываться в техническое: мы создаем экземпляр контракта, выбираем какие функции из него собираемся тестировать в связке, а потом в случайном порядке подаем им случайные значения на вход. Если какая то последовательность вызовов функции нарушает наш инвариант, то мы увидим в логах всю цепочку вызовов, приведшую к ошибке. Огромное отличие от теста без сохранения состояния в том, что мы к тому же можем ограничивать подаваемые на вход значения, чтобы уменьшить ширину диапазона из которого берутся случайные значения + прописать N акторов от лица которых вызываются транзакции. Как внедрять: - Hardhat можно использовать специализированный fuzzer Echidna (https://github.com/crytic/echidna), но с 2025 года имеет встроенный fuzzer - Foundry имеет встроенный fuzzer 7 слой. Formal Verification Если фаззеры закидывают функции случайными данными и пытаются таким образом вызвать сбой, то методы формальной верификации пытаются найти математическое доказательство корректности функции. Крайне мощный инструмент, обладающий своей спецификой и ограничениями по применению, но по сути не имеющий аналогов. На Cyfrin его изучение закинули в отдельный курс (https://updraft.cyfrin.io/courses/formal-verification) Как внедрять: - Такой анализатор есть прямо в solc (компилятор Solidity), использует SMT-солверы, вызывать через консоль - Использовать стороннее ПО, такое как Halmos (https://github.com/a16z/halmos), Certora (https://www.certora.com/) Этот пост конечно не является железным требованием ко всем кодовым базам, но чем больше слоев, тем лучше. Так же стоит понимать, что каких-то слоев в случайном порядке может не быть и это нормально Каждая команда исходит из того, сколько у них времени и ресурсов и разные способы проверки кода требуют кратно разных затрат https://t.me/web3securityresearch
0 reply
0 recast
7 reactions