Верифікація смарт-контрактів
Смарт-контракти розроблені як «бездовірчі», що означає, що користувачам не потрібно довіряти третім сторонам (наприклад, розробникам і компаніям) перед взаємодією з контрактом. Як обов'язкова умова для бездовірності, користувачі та інші розробники повинні мати можливість верифікувати вихідний код смарт-контракту. Верифікація вихідного коду гарантує користувачам і розробникам, що опублікований код контракту є тим самим кодом, який виконується за адресою контракту в блокчейні Етеріуму.
Важливо розрізняти «верифікацію вихідного коду» та «формальну верифікацію». Верифікація вихідного коду, яка буде детально пояснена нижче, означає перевірку того, що наданий вихідний код смарт-контракту мовою високого рівня (наприклад, Solidity) компілюється в той самий байт-код, який буде виконуватися за адресою контракту. Натомість формальна верифікація описує перевірку правильності смарт-контракту, тобто того, що контракт поводиться так, як очікується. Хоча це залежить від контексту, верифікація контракту зазвичай означає верифікацію вихідного коду.
Що таке верифікація вихідного коду?
Перед розгортанням смарт-контракту у Віртуальній машині Етеріуму (EVM) розробники компілюють вихідний код контракту — інструкції, написані мовою Solidity або іншою мовою програмування високого рівня, — у байт-код. Оскільки EVM не може інтерпретувати високорівневі інструкції, компіляція вихідного коду в байт-код (тобто низькорівневі машинні інструкції) є необхідною для виконання логіки контракту в EVM.
Верифікація вихідного коду — це порівняння вихідного коду смарт-контракту та скомпільованого байт-коду, використаного під час створення контракту, для виявлення будь-яких відмінностей. Верифікація смарт-контрактів має значення, оскільки заявлений код контракту може відрізнятися від того, що виконується в блокчейні.
Верифікація смарт-контракту дозволяє дослідити, що робить контракт, за допомогою мови вищого рівня, якою він написаний, без необхідності читати машинний код. Функції, значення та, як правило, імена змінних і коментарі залишаються такими ж, як і в оригінальному вихідному коді, який компілюється та розгортається. Це значно полегшує читання коду. Верифікація вихідного коду також забезпечує наявність документації до коду, щоб кінцеві користувачі знали, для чого призначений смарт-контракт.
Що таке повна верифікація?
Деякі частини вихідного коду не впливають на скомпільований байт-код, наприклад, коментарі або імена змінних. Це означає, що два вихідні коди з різними іменами змінних і різними коментарями зможуть верифікувати один і той самий контракт. З огляду на це, зловмисник може додати оманливі коментарі або дати імена змінним, що вводять в оману, у вихідному коді та верифікувати контракт за допомогою вихідного коду, який відрізняється від оригінального.
Цього можна уникнути, додавши до байт-коду додаткові дані, які слугуватимуть криптографічною гарантією точності вихідного коду та відбитком інформації про компіляцію. Необхідна інформація міститься в метаданих контракту Solidity (opens in a new tab), і хеш цього файлу додається до байт-коду контракту. Ви можете побачити це в дії на майданчику метаданих (opens in a new tab)
Файл метаданих містить інформацію про компіляцію контракту, включаючи вихідні файли та їхні хеші. Це означає, що якщо зміняться будь-які налаштування компіляції або навіть один байт в одному з вихідних файлів, файл метаданих зміниться. Відповідно, хеш файлу метаданих, який додається до байт-коду, також зміниться. Це означає, що якщо байт-код контракту + доданий хеш метаданих збігаються з наданим вихідним кодом і налаштуваннями компіляції, ми можемо бути впевнені, що це саме той вихідний код, який використовувався в оригінальній компіляції, і жоден байт не відрізняється.
Цей тип верифікації, який використовує хеш метаданих, називається «повною верифікацією (opens in a new tab)» (також «ідеальною верифікацією»). Якщо хеші метаданих не збігаються або не враховуються під час верифікації, це буде «частковий збіг», що наразі є більш поширеним способом верифікації контрактів. Без повної верифікації можна вставити шкідливий код (opens in a new tab), який не буде відображений у верифікованому вихідному коді. Більшість розробників не знають про повну верифікацію і не зберігають файл метаданих своєї компіляції, тому часткова верифікація досі була фактичним методом верифікації контрактів.
Чому верифікація вихідного коду важлива?
Бездовірність
Бездовірність є, мабуть, найбільшою передумовою для смарт-контрактів і децентралізованих застосунків (dapp). Смарт-контракти є «незмінними» і не можуть бути змінені; контракт виконуватиме лише ту бізнес-логіку, яка визначена в коді на момент розгортання. Це означає, що розробники та підприємства не можуть підробити код контракту після розгортання в Етеріумі.
Щоб смарт-контракт був бездовірчим, код контракту має бути доступним для незалежної верифікації. Хоча скомпільований байт-код для кожного смарт-контракту є загальнодоступним у блокчейні, низькорівневу мову важко зрозуміти — як розробникам, так і користувачам.
Проєкти зменшують припущення довіри, публікуючи вихідний код своїх контрактів. Але це призводить до іншої проблеми: важко верифікувати, що опублікований вихідний код збігається з байт-кодом контракту. У цьому сценарії цінність бездовірності втрачається, оскільки користувачі повинні довіряти розробникам, що ті не змінять бізнес-логіку контракту (тобто шляхом зміни байт-коду) перед його розгортанням у блокчейні.
Інструменти верифікації вихідного коду надають гарантії того, що файли вихідного коду смарт-контракту збігаються з кодом асемблера. Результатом є бездовірча екосистема, де користувачі не довіряють сліпо третім сторонам, а натомість верифікують код перед тим, як внести кошти в контракт.
Безпека користувачів
Зі смарт-контрактами зазвичай на кону стоять великі гроші. Це вимагає вищих гарантій безпеки та верифікації логіки смарт-контракту перед його використанням. Проблема полягає в тому, що недобросовісні розробники можуть обдурити користувачів, вставивши шкідливий код у смарт-контракт. Без верифікації шкідливі смарт-контракти можуть мати бекдори (opens in a new tab), суперечливі механізми контролю доступу, вразливості, які можна експлуатувати, та інші речі, що ставлять під загрозу безпеку користувачів і залишаються непоміченими.
Публікація файлів вихідного коду смарт-контракту полегшує зацікавленим особам, таким як аудитори, оцінку контракту на наявність потенційних векторів атак. Коли кілька сторін незалежно верифікують смарт-контракт, користувачі отримують сильніші гарантії його безпеки.
Як верифікувати вихідний код для смарт-контрактів Етеріуму
Розгортання смарт-контракту в Етеріумі вимагає надсилання транзакції з корисним навантаженням даних (скомпільованим байт-кодом) на спеціальну адресу. Корисне навантаження даних генерується шляхом компіляції вихідного коду, плюс аргументи конструктора (opens in a new tab) екземпляра контракту, додані до корисного навантаження даних у транзакції. Компіляція є детермінованою, тобто вона завжди дає однаковий результат (тобто байт-код контракту), якщо використовуються ті самі вихідні файли та налаштування компіляції (наприклад, версія компілятора, оптимізатор).
Верифікація смарт-контракту в основному включає наступні кроки:
-
Введіть вихідні файли та налаштування компіляції в компілятор.
-
Компілятор виводить байт-код контракту.
-
Отримайте байт-код розгорнутого контракту за заданою адресою.
-
Порівняйте розгорнутий байт-код із перекомпільованим байт-кодом. Якщо коди збігаються, контракт верифікується за допомогою наданого вихідного коду та налаштувань компіляції.
-
Крім того, якщо хеші метаданих у кінці байт-коду збігаються, це буде повний збіг.
Зверніть увагу, що це спрощений опис верифікації, і існує багато винятків, які не працюватимуть із цим, наприклад, наявність незмінних змінних (opens in a new tab).
Інструменти верифікації вихідного коду
Традиційний процес верифікації контрактів може бути складним. Саме тому ми маємо інструменти для верифікації вихідного коду смарт-контрактів, розгорнутих в Етеріумі. Ці інструменти автоматизують значну частину верифікації вихідного коду, а також курують верифіковані контракти на користь користувачів.
Etherscan
Хоча Etherscan здебільшого відомий як оглядач блоків Етеріуму, він також пропонує сервіс верифікації вихідного коду (opens in a new tab) для розробників і користувачів смарт-контрактів.
Etherscan дозволяє перекомпілювати байт-код контракту з оригінального корисного навантаження даних (вихідний код, адреса бібліотеки, налаштування компілятора, адреса контракту тощо). Якщо перекомпільований байт-код пов'язаний із байт-кодом (і параметрами конструктора) ончейн-контракту, то контракт верифіковано (opens in a new tab).
Після верифікації вихідний код вашого контракту отримує позначку «Verified» (Верифіковано) і публікується на Etherscan для аудиту іншими користувачами. Він також додається до розділу Verified Contracts (opens in a new tab) — репозиторію смарт-контрактів із верифікованими вихідними кодами.
Etherscan є найбільш використовуваним інструментом для верифікації контрактів. Однак верифікація контрактів на Etherscan має недолік: вона не порівнює хеш метаданих ончейн-байт-коду та перекомпільованого байт-коду. Тому збіги в Etherscan є частковими.
Більше про верифікацію контрактів на Etherscan (opens in a new tab).
Blockscout
Blockscout (opens in a new tab) — це оглядач блоків із відкритим вихідним кодом, який також надає сервіс верифікації контрактів (opens in a new tab) для розробників і користувачів смарт-контрактів. Як альтернатива з відкритим вихідним кодом, Blockscout пропонує прозорість у тому, як виконується верифікація, і дозволяє спільноті робити внески для покращення процесу верифікації.
Подібно до інших сервісів верифікації, Blockscout дозволяє верифікувати вихідний код вашого контракту шляхом перекомпіляції байт-коду та порівняння його з розгорнутим контрактом. Після верифікації ваш контракт отримує статус верифікації, а вихідний код стає загальнодоступним для аудиту та взаємодії. Верифіковані контракти також перераховані в репозиторії верифікованих контрактів (opens in a new tab) Blockscout для зручного перегляду та виявлення.
Sourcify
Sourcify (opens in a new tab) — це ще один інструмент для верифікації контрактів, який має відкритий вихідний код і є децентралізованим. Це не оглядач блоків, і він лише верифікує контракти в різних мережах на базі EVM (opens in a new tab). Він діє як публічна інфраструктура для створення інших інструментів на його основі та має на меті забезпечити більш зручну для людини взаємодію з контрактами за допомогою ABI та коментарів NatSpec (opens in a new tab), які містяться у файлі метаданих.
На відміну від Etherscan, Sourcify підтримує повні збіги з хешем метаданих. Верифіковані контракти обслуговуються в його публічному репозиторії (opens in a new tab) через HTTP та IPFS (opens in a new tab), що є децентралізованим сховищем з адресацією за вмістом (opens in a new tab). Це дозволяє отримувати файл метаданих контракту через IPFS, оскільки доданий хеш метаданих є хешем IPFS.
Крім того, можна також отримати файли вихідного коду через IPFS, оскільки хеші IPFS цих файлів також містяться в метаданих. Контракт можна верифікувати, надавши файл метаданих і вихідні файли через його API або інтерфейс користувача (opens in a new tab), або за допомогою плагінів. Інструмент моніторингу Sourcify також відстежує створення контрактів у нових блоках і намагається верифікувати контракти, якщо їхні метадані та вихідні файли опубліковані в IPFS.
Більше про верифікацію контрактів на Sourcify (opens in a new tab).
Tenderly
Платформа Tenderly (opens in a new tab) дозволяє розробникам Web3 створювати, тестувати, контролювати та керувати смарт-контрактами. Поєднуючи інструменти налагодження з можливістю спостереження та інфраструктурними будівельними блоками, Tenderly допомагає розробникам прискорити розробку смарт-контрактів. Щоб повною мірою використовувати функції Tenderly, розробникам потрібно виконати верифікацію вихідного коду (opens in a new tab) за допомогою кількох методів.
Можна верифікувати контракт приватно або публічно. Якщо смарт-контракт верифіковано приватно, він видимий лише вам (та іншим учасникам вашого проєкту). Публічна верифікація контракту робить його видимим для всіх, хто використовує платформу Tenderly.
Ви можете верифікувати свої контракти за допомогою панелі керування (opens in a new tab), плагіна Tenderly Hardhat (opens in a new tab) або CLI (opens in a new tab).
Під час верифікації контрактів через панель керування вам потрібно імпортувати вихідний файл або файл метаданих, згенерований компілятором Solidity, адресу/мережу та налаштування компілятора.
Використання плагіна Tenderly Hardhat забезпечує більший контроль над процесом верифікації з меншими зусиллями, дозволяючи вам вибирати між автоматичною (без коду) та ручною (на основі коду) верифікацією.
