Почему отсутствие единого языка написания смарт-контрактов для EVM — это хорошо и полезно для экосистемы Эфириума? Что такое Vyper и почему он стал вторым по популярности языком EVM и в чем его преимущества над Solidity?
Что такое Vyper
Когда речь идет о программировании смарт-контрактов для EVM, обычно вспоминают о языке Solidity. Однако на самом деле это не единственное решение. Существует вполне серьезная альтернатива в виде языка Vyper, который успел приобрести какую-никакую поддержку со стороны сообщества.
«Змеиность» названия Vyper отнюдь не случайна: язык создан на базе одного из самых популярных языков программирования в мире — Python. Но если «Пайтон» — это универсальный язык, на котором можно писать практически все что угодно, то Vyper предназначен исключительно для работы с виртуальной машиной Эфириума.
Vyper — это высокоуровневый язык, специально разработанный с учетом потребности в безопасности, простоте и читабельности кода смарт-контрактов, разворачиваемых в EVM-совместимых блокчейнах. Читабельность помогает разработчикам обнаруживать ошибки и уязвимости в своем коде перед развертыванием контрактов.
Vyper создан лично соучредителем Ethereum Виталиком Бутериным и впервые был представлен в 2017 году.
Философия этого инструмента может быть удачно передана следующей фразой: «Vyper был создан для минимизации вероятности того, что программист нечаянно выстрелит себе в ногу». То есть язык задуман таким образом, что активно мешает разработчику напортачить с кодом смарт-контракта и потерять деньги. Безопасность и читабельность, к сожалению, имеют свою цену: пришлось пожертвовать гибкостью и функциональностью.
Почему Vyper стал популярным
Главное, что притягивает разработчиков к Vyper — простота, удобство и читабельность кода. Другим немаловажным фактором является похожесть синтаксиса Vyper и Python. Коль скоро последний является самым популярным языком программирования в мире (по данным ресурса TIOBE), для многих программистов разобраться в Vyper легче.
Solidity, главный конкурент, сложнее Vyper.
Во-первых, на нем проще допустить или обнаружить ошибку, особенно для новичков в программировании смарт-контрактов.
Во-вторых, синтаксис Solidity базируется на JavaScript, который менее популярный в сравнении с Пайтоном (в индексе TIOBE JS никогда не поднимался выше топ-6).
Также популярности Vyper прибавляют высокий уровень безопасности и возможности для аудита кода.
Чем пришлось пожертвовать во имя простоты и безопасности
Для того, чтобы программист ненароком не допустил ошибку или не создал уязвимость, создатели Vyper намеренно несколько урезали функционал. Перечислим основные жертвы, на которые они решились.
Модификаторы. Например, в Solidity можно определить функцию foo() mod1 { … }, где mod1 будет определяться в другом месте кода, чтобы включить проверку, выполняемую до или после исполнения. В Vyper подобного нет, потому что бьет по понятности кода.
Наследование классов. Наследование позволяет определить класс, который унаследует все методы и свойства другого класса. По мнению разработчиков, наследование существенно усложнит структуру кода, ударив по читабельности и понятности, поэтому от поддержки опции решили отказаться.
Ассемблерная вставка (inline assembly). Возможность компилятора встраивать низкоуровневый код (в случае с Solidity написанный на Yul) в программу, написанную на высокоуровневом языке. И от этой функции создатели Vyper отказались во имя читабельности.
Также в Vyper недоступны перегрузки функций и операторов, рекурсивные функции, бесконечные циклы и двоичные числа с фиксированной точкой.
Стоит отметить: у подобных ограничений есть один важный скрытый плюс. Поскольку в Vyper попросту отсутствуют описанные выше функции, при компиляции кода ему не нужно выполнять лишние проверки. Это хорошо, так как каждая операция при развертывании смарт-контракта требует платы за газ. Поэтому, например, в Solidity, чтобы удостовериться, что смарт-контракт не будет неожиданно тратить криптовалюту впустую, при компиляции кода выполняются дополнительные проверки. У Vyper тоже есть такие проверки, но их существенно меньше, что позволяет экономить на газе.
Особенности работы с памятью
Помимо вопросов читабельности, удобства кодинга и связанных с ними особенностей Vyper, отдельного внимания заслуживает работа Vyper с памятью.
В отличие от Python, у Vyper отсутствует динамическая типизация. То есть тип каждой переменной должен быть строго определен заранее. Это связано с отсутствием у Vyper динамических структур данных. Программисту приходится точно указывать, насколько большим будет объект, который он хочет записать в память. Это одновременно и плюс, и минус.
С одной стороны, программист вынужден работать только с данными заранее определенного размера, иначе Vyper попросту не сможет записать их в память. Но, с другой, плюс от такой логики работы с памятью может перевешивать минусы.
При компиляции Vyper заранее понимает, сколько памяти он должен выделить для каждого объекта. Это позволяет не иметь указателей свободной памяти (free memory pointer), которые есть у Soidity. Этот поинтер всегда указывает на свободную ячейку памяти, следующую за последней занятой. Каждый раз, когда в память что-то записывается, указатель перемещаются к следующей ближайшей свободной ячейке, указывая тем самым, куда будут записываться данные дальше. Это, с одной стороны, позволяет Solidity иметь динамические структуры данных, но с другой стороны, работа указателя увеличивает расходы на газ.
Поэтому, если получится написать смарт-контракт, не прибегая к динамической структуре данных, то на Vyper он будет эффективнее расходовать газ в сравнении с аналогичным контрактом на Solidity.
Эффективность траты газа
На ресурсе Chainlink провели сравнительное исследование расходования газа в Vyper, Solidity и низкоуровневых Huff и Yul. Последние, понятно, из-за низкоуровневости вне конкуренции в эффективности траты газа. Но эта же самая низкоуровневость мешает конкурировать в популярности с высокоуровневыми Vyper и Solidity, где банально в разы больше разработчиков.
Низкоуровневые языки оставляют гораздо больший простор для ошибки. Они выполняют ровно то, что от них требует разработчик. И если он где-то допустит ошибку, Huff и Yul подобного не простят. А вот в Vyper и Solidity велика вероятность, что встроенные проверки уберегут программиста от глупостей.
В лиге высокоуровневых языков Vyper показал себя немного лучше Solidity. Создание простого контракта на Vyper потребовало чуть больше 75 000 gwei, а на Solidity = более 80 000. Запись и последующее чтение числа 77 сэкономило на Vyper, по сравнению с Solidity, примерно 100 gwei.
Если посмотреть на опкоды, то можно обнаружить, что Vyper и Solidity выполняют операции немного по-разному. То есть они не одинаково переносят инструкции из высокоуровнего кода в понятные для EVM опкоды. Из-за этого и возникает разница в трате за газ.
Недостатки Vyper
Vyper пока все же гораздо менее популярен, чем Solidity, а это значит, что сообщество разработчиков на Vyper элементарно меньше. Это может затруднить поиск ресурсов и поддержки для проектов на Vyper.
Скорость обновления языка ниже, чем у Solidity, поэтому придется дольше дожидаться появления новых функций. Более того, из-за встроенных в Vyper ограничений, многие новинки, доступные у языка-конкурента, могут попросту не появиться в Vyper.
И, наконец, Vyper хуже встроен в инфраструктуру Web3, поэтому многие платформы поддерживают Solidity, но не имеют поддержку Vyper.
Взлом Curve Finance
В продолжение темы с недостатками стоит упомянуть взлом смарт-контрактов, написанных на Vyper, который произошел с проектом Curve Finance.
30 июля 2023 года несколько пулов ликвидности Curve Finance подверглись взлому, связанному с уязвимостями некоторых версий компилятора Vyper (уязвимость была обнаружена в версиях 0.2.15, 0.2.16 и 0.3.0). Расследование показало, что некоторые версии компилятора Vyper неправильно реализовали защиту повторного входа, предотвращающую одновременное выполнение нескольких функций путем блокировки контракта.
После того как информация об эксплойте оказалась в сети, многие хакеры присоединились к действию. Причем не обязательно со злым умыслом. Некоторым этичным хакерам удалось вернуть Curve Finance часть средств. Но в целом урон получился ощутимым: размер убытков достиг более 61 млн долларов.
С другой стороны, любой смарт-контракт, написанный на любом языке программирования, может потенциально стать жертвой взлома или эксплойта. Уберечься от этого на все 100% едва ли возможно.
Вывод
Vyper представляет собой вполне конкурентное решение для разработки смарт-контрактов на виртуальной машине Эфириума. Язык относительно прост в освоении, предлагая хороший уровень безопасности и экономно расходуя газ. Но есть и оборотная сторона: функционал не такой гибкий как у Solidity, на котором можно развернуть более сложные проекты.