Solidity. Смарт контракты и аудит – Telegram
Solidity. Смарт контракты и аудит
2.62K subscribers
246 photos
7 videos
18 files
547 links
Обучение Solidity. Уроки, аудит, разбор кода и популярных сервисов
Download Telegram
Blockchain reorgs. Часть 1

Эту тему мне приходилось касаться только на аудитах. Ни у себя на канале, ни на других каналах я не встречал информации про такое событие как реорганизация блоков в блокчейне, и чем это может быть опасно. Возможно, материал и был, но мне он так и не встретился. Поэтому следующие несколько постов мы посвятим этой теме.

В Web3 мы часто слышим идиому «блокчейн неизменен», но бывают случаи, когда это не так, точнее, он становится практически неизменным (достигает окончательности) только по прошествии некоторого времени с момента майнинга блока, содержащего транзакции пользователей. Это связано с событиями, называемыми реорганизациями блокчейна, или сокращенно reorg.

Реорганизация - это событие, когда блок, который был частью канонической цепи, перестает быть частью канонической цепи, потому что его вытесняет конкурирующий блок.

Реорганизации происходят из-за более мягкого способа работы клиента проверки блокчейна. Алгоритм, определяющий, какая цепь является канонической (правило выбора форка), при определенных обстоятельствах может прийти к выводу, что текущая история цепей не является оптимальной, и выбрать другую цепь из тех, что предоставляют конкурирующие майнеры (цепочки форков), чтобы стать канонической цепью.

Когда происходит перестройка блока, то, будучи внешним наблюдателем цепочки, вы видите, что:

1. Несколько блоков были отброшены и заменены другими;

2. Это не означает, что все транзакции в исходных блоках были отброшены, большое количество транзакций, вероятно, все еще будет включено в новые блоки, возможно, даже все, но не в том же порядке;

Реорганизации появляются чаще, чем люди думают. Используя такие сканеры, как polygonscan.com/blocks_forked, для Polygon reorgs, вы можете увидеть, что они появляются часто.

При разработке или аудите протоколов, которые могут быть уязвимы к проблемам реорганизации, необходимо учитывать некоторые моменты, характерные для каждой цепи. В качестве ориентира можно использовать таблицу на скрине.

Примечания и наблюдения

- Приведенные на скрине данные были собраны либо со сторонних агрегаторов, либо с сайтов, напрямую отображающих исходные данные. Они также взяты после любых крупных изменений в сети, например, для Ethereum после PoS и для BNB Chain после их последних крупных изменений в масштабируемости, которые резко снизили скорость реорганизации.

- При принятии решения о том, сколько блоков ждать перед подтверждением транзакции вне цепи в чувствительных системах (например, при переходе с криптовалюты на фиат), лучше всего подождать на несколько блоков больше, чем наибольшая глубина реорганизации на этой цепи, которая имела место в прошлом.

- Например, депозиты на CEX от Polygon могут ждать даже 200 блоков, прежде чем будут считаться окончательными.

Системы, основанные на случайной составляющей в сети

Протоколы, содержащие случайный компонент, естественным образом подвержены влиянию реорганизации блокчейна. Такими протоколами могут быть ставки, казино, игры со случайной системой вознаграждения, практически все, что вычисляет случайность с помощью оракула.

Пример ситуаций, которые могут возникнуть:

- игрок выигрывает хорошее вознаграждение в случайном розыгрыше, но из-за реорганизации блокчейна теряет его;

- азартный игрок проигрывает в игре в кости, но благодаря реорганизации блокчейна он теперь фактически выигрывает;

На практике для вычисления случайного числа часто используется VRF (Verifiable Random Function) от Chainlink. Этот API принимает время подтверждения блока, которое, если верить документации, представляет собой:

- сколько блоков служба VRF ждет, прежде чем записать выполнение в сеть, чтобы сделать потенциальные атаки на перезапись невыгодными в контексте вашего приложения и его стоимости под риском.

Для того, чтобы смягчить эту проблему, достаточно выбрать подходящее время подтверждения блока.

#reorg
👍6🙏1
P.S. Скрин, который забыл прикрепить к предыдущему посту.
Blockchain reorgs. Часть 2

Продолжаем наш разговор про реорганизацию блокчейна.

Off-ramp системы

Под криптовалютным off-ramp понимается процесс обмена криптовалют на фиатную валюту. К системам, осуществляющим офф-рампинг криптовалют, относятся:

- централизованные биржи (CEX);

- провайдеры криптовалют в фиат;

Криптовалютные депозиты в этих системах подтверждаются после определенного количества блоков, прошедших с момента транзакции, чтобы смягчить любые проблемы, которые могут быть вызваны перестройкой блокчейна.

В этой серии постов приведены некоторые конкретные требования к подтверждению блоков, которые существуют на известных CEX. Например, Coinbase требует 35 подтверждений блоков для депозитов ETH, в то время как Binance - только 12.

По наблюдениям, CEX склонны сильно затягивать с подтверждением. Например, реорганизация блокчейна Ethereum более чем на 2 блока не происходила уже несколько лет.

Off-ramp системы, особенно CEX, являются привлекательной целью для атак 51%. В прошлом было несколько случаев, когда злоумышленники получали 51% ресурсов проверки сети (коэффициент хеширования) и инициировали вывод средств на нескольких биржах, а затем реорганизовывали цепочку, чтобы повторно инициировать вывод средств на других биржах.

Наиболее заметные атаки 51% затрагивают токены Verge, Ethereum Classic, Bitcoin Gold, Feathercoin и Vertcoin.

Смягчить последствия этой формы атаки не так просто. Одним из компонентов решения является чрезмерное увеличение количества требуемых подтверждений. Однако в таких случаях этого недостаточно, поскольку захват сети может длиться неопределенное количество времени. Необходимо внедрить решение для мониторинга сети в сочетании с приостановкой снятия/пополнения средств.

Протоколы, которые требуют от пользователей создать что-то, а затем взаимодействовать с этим в два этапа

Этот тип проблем с реорганизацией наиболее часто встречается в данной категории уязвимостей. Они возникают, когда протокол требует от пользователей сначала создать или инициировать компонент, а затем, в другой транзакции, взаимодействовать с ним.

Еще одним важным и ключевым условием является то, что развернутые контракты используют ключевое слово в Solidity "new" для создания контракта (или опкод CREATE). Обе эти процедуры полагаются на nonce вызывающего контракта для определения адреса вновь развернутого контракта и не учитывают никаких пользовательских данных.

Например, протокол использует шаблон factory для развертывания контрактов, чьи функции не имеют прав доступа. Скажем, логика фабрики развертывает контракт одним вызовом, предоставляя специальные разрешения развертывающему. После развертывания пользователь отправляет депозит только что развернутому контракту.

Примерный сценарий атаки в описанном выше случае:

1. Alice создает Vault через контракт фабрики (транзакция A);

2. затем Alice вносит в Vault токены (транзакция B);

3. происходит реорганизация блока, и транзакция A отбрасывается (транзакция B все еще существует);

4. обычно транзакция B возвращается, если выполняется;

5. Bob развертывает свой Vault, который первоначально сделала Alice (через фронтран), и из-за базовой проблемы оно= создается по тому же адресу, что и первоначальное хранилище

6. депозит Alice попадает в Bob Vault, и тот может его снять;

Для того, чтобы решить эту проблему, используйте опкод create2, а соль должна содержать элементы, характерные для вызывающей стороны (например, хэш на входы плюс msg.sender).

#reorg
👍2
Содержание предыдущих постов

Что-то давно я не делал подборку с темами прошедших постов, а ведь их собралось не мало практически за последние полгода. По традиции сделал небольшое оглавления с быстрыми ссылками для удобства поиска.

P.S. Также буду рад и признателен репостам.


Обучающие посты

1. Solidity hints. Часть 22

2. Solidity hints. Часть 23

3. Solidity hints. Часть 24

4. Solidity hints. Часть 25

5. Merkle-Patricia Trees. 14 постов

6. Низкоуровневый вызов и высокоуровневый вызов в Solidity. 2 поста

7. RSA алгоритмы. 4 поста

8. Самые популярные типы DAO. 3 поста

9. Обновляемые контракты (Transparent proxy). 5 постов

10. Calldata Encoding. 3 поста

11. Понимание метаданных смарт-контракта. 2 поста

12. Пара слов о Passkeys

13. Все, что нужно знать об интеграции Chainlink. 3 поста

14. Работа с мультисиг кошельками. 7 постов

15. Blockchain reorgs. 2 поста


Видео

16. Запись стрима "Подготовка протокола (dApp) к аудиту"

17. Запись стрима "ERC4626: проблемы и решения"

18. Пробы записи видео и разбор функций

19. Постфикс и префикс в Solidity

20. Взлом контракта через calldata

21. Опасный модификатор


Для начинающих аудиторов

22. Небольшая история о путешествии в мире аудита

23. Челлендж: 50 не валидных репортов

24. Нужно ли доводить аудит до конца?

25. Коротко о двойных стандартах в конкурсных аудитах

26. Роудмап: Как стать аудитором смарт контрактов. 3 поста

27. Конкурсные аудиты с пулом "по условию" - Conditional Pool

28. Упражнение для начинающих аудиторов

29. Про подготовку к аудиту

30. Ловушка аудитора и недостаток валидации


Остальное

31. Минимальные требования для работы

32. Тестирование != тестирование

33. Перспективы для новичков в web3

34. Компилятор тоже умеет шутить


Приятного изучения и хорошего дня!

#offtop
🔥15
🧨 Программа 1 модуля курса, 3 поток!

Сегодня хочу показать вам программу модуля, над которой я работал последние два месяца. И это что-то невероятное, чем я очень горжусь!

Прежде чем приступать к переработке модуля, я просмотрел все вопросы учеников с прошлых модулей, программы других похожих курсов, роадмапы и многое другое. В этом модуле будет собрана информация, которая даст максимально полное представление для ученика о мере Эфириума и разработки смарт контрактов!

Во-первых, появилось много сетей различных уровней и их количество будет расти, поэтому ученику нужно дать представление: зачем это нужно, как работает и чем отличается от всех остальных.

Во-вторых, сам Эфириум претерпевает изменения все более крупного масштаба, и нужно понимать, всю внутреннюю механику процесса.

В-третьих, я понял, что вместе с базовыми знаниями Solidity нужно давать объяснение ученикам, как это происходит на уровне виртуальной машины Эфириум. Простыми словами с отсылками к Yellow Pages.

В-четвертых, было бы здорово, если бы после модуля у ученика был бы некоторый материал для самостоятельной практики, на случай, если он будет не готов идти на последующие модули и потребуется время, чтобы все усвоить после первого.

P.S. Сразу скажу, что модуль будет запускаться, если будет набрано достаточно количество учеников. Если же нет - он будет отложен на некоторый срок. Поэтому голосование после поста крайне желательно!

Итак, вот программа модуля:


Неделя 1

Урок 1. Введение в программирование: код и алгоритмы.
Урок 2. Web3 и его компоненты.
Урок 3. Блокчейн, сайдчейн и различные уровни сетей.
Урок 4. Что такое сеть Эфириум?
Урок 5. Архитектура Эфириум.

Дополнительно: Консенсус (общее);
Дополнительно: Состояния сети и Деревья;

+30 вопросов для самопроверки


Неделя 2

Урок 6. Введение в Solidity.
Дополнительно: Типы аккаунтов. Что такое транзакция?

Урок 7. Начало работ с Remix.
Дополнительно: Правила именований в контрактах;
Дополнительно: Процесс создания контрактов на уровне EVM;

Урок 8. Переменные в Solidity.
Дополнительно: Общий обзор всех типов данных.

Урок 9. Тип данных: bool.
Дополнительно: Какие операторы существуют?

Урок 10. Тип данных: string.
Дополнительно: История форков;

+30 вопросов для самопроверки


Неделя 3

Урок 11. Тип данных: uint/int.
Дополнительно. Условия в программировании;

Урок 12. Тип данных: bytes.
Дополнительно: Почему важен шардинг для EVM?

Урок 13. Тип данных: array.

Урок 14. Тип данных: enum.

Урок 15. Тип данных: mapping.

+30 вопросов для самопроверки


Неделя 4

Урок 16. Event и error в коде.
Дополнительно: Больше о событиях и логировании;

Урок 17. Функции.

Урок 18. Валидация ошибок в коде.

Урок 19. Циклы и итерации.

Урок 20. Модификаторы.
Дополнительно: Выполнение транзакции на уровне EVM;

+30 вопросов для самопроверки


Неделя 5

Урок 21. Структуры и вложенности

Урок 22. Глобальные переменные
Дополнительно: Память EVM.
Дополнительно: Работа с памятью EVM. Общее.

Урок 23. Наследования

Практикум 1

Урок 24. Интерфейсы
Дополнительно: Вызов между контрактами на уровне EVM;

+30 вопросов для самопроверки


Неделя 6

Урок 25. Библиотеки
Дополнительно. Знакомство с библиотеками Open Zeppelin;

Урок 26. Call, statickcallm
Дополнительно: Межсетевое взаимодействие: проблемы и решения;

Урок 27. Delegatecall

+15 вопросов для самопроверки

Практикум 2

Бонус: задачник для самостоятельной практики в Remix на 30 заданий!


Итого: 6 недель, 27 уроков, 17 дополнительных уроков по EVM, 165 вопросов для самопроверки, 30 практических заданий, 2 практикума!

Формат - текстовые посты с домашними заданиями в закрытой группе в Телеграм, видео только в дополнительных материалах. Сам канал удаляться не будет, информация в нем останется с вами навсегда.

Уверен, что этот модуль будет одним из самых "мясных" на рынке!

Ниже будет опрос для тех, кто хотел бы пойти на обучения. Прошу проголосовать тех, кто заинтересован.

Всем прекрасного дня и настроения!

#курс #обучение
🔥9💯2👍1
Про vibe coding и Solidity

Когда все вокруг говорят, что нейросети скоро заменят программистов, я решил проверить это на практике. Взял отчасти незнакомый стек — Python + React + MySQL — и поставил задачу: создать крипто мессенджер с end-to-end шифрованием. Не вникая в код, просто давая указания нейронке.

Итог? Три дня борьбы с бессмысленными правками, тоннами логов и внезапными ошибками в рабочих частях кода. Нейросеть путала версии библиотек, "чинила" то, что не ломалось, и в итоге выдала монструозный проект, который проще переписать с нуля, чем отладить.

Это был фейл...

1. В самом начале я столкнулся с проблемой версий библиотек и Python, библиотек и React+Vite... Я использовал рекомендованный набор библиотек от нейронок и когда возникли ошибки, нейронки такие: "А ты не знал?! Как жаль... Вот так нужно все перенастроить...". Ок, пара часов возни и все установлено.

2. Потом мы создали компоненты для фронтенда и подключили авторизацию. Вроде, все было ок, пока не потребовалось создание секретной фразы для криптографии. Тут пошли "танцы с бубном".

3. Невообразимое логирование, куча отладочных файлов и тестов. В итоге, папка проекта и сам код раздулись просто комарно. Я уже сдался и пошел настраивать все сам и вникать в код.

4. Дальше был Python. При, казалось бы, огромной базе знаний в сети, нейронки просто не смогли подключиться к базе данных. Запускались куча терминалов, вводились одинаковые команды. И снова логирование...

5. Что самое плохое было, так это то, что нейронка пыталась корректировать файлы, который не нуждались в этом. Создавая связь с базой данных, он исправлял и компоненты фронтенда, и версии библиотек с их переустановкой и массой других не нужных действий.

И это все в работе с популярными языками программирования. С Solidity дела обстоят куда серьезнее.

Нейронки плохо понимают контекст. Они не видят последствий. Они просто комбинируют куски кода из интернета.

Я учу Solidity не для того, чтобы вы писали всё вручную. Я учу вас понимать, что делает нейросеть. Видеть её ошибки. Правильно ставить ей задачи. Потому что в мире, где любой может сгенерировать контракт за минуту, настоящий навык — это умение отличить рабочую вещь от финансовой бомбы.

Курс стартует 5 мая. Первый модуль — база, чтобы читать и разбирать любой контракт. Второй — практика с упором на безопасность. Это тот минимум, после которого ты сможешь работать с нейросетями, а не надеяться на них.

P.S. Если вы разработчик и хотите попробовать реализовать задумку с крипто мессенджером, я могу дать технические описания, которые мы создавали с нейронками, и вы пройдете мои "страдания".

#курс
👍143🔥1
Последний поток курса в таком формате

Три года мы делали идеальный курс для новичков в Solidity, но всё меняется.

Третий поток в Telegram станет последним в таком формате, и это отличный шанс пройти обучение именно с живой поддержкой и общением.

Сейчас у вас есть возможность учиться в небольшой группе, где я проверяю задания, отвечаю на вопросы и помогаю разбирать сложные моменты. Такой формат отлично подходит тем, кто ценит персональный подход и хочет сразу получать обратную связь.

В следующем году курс переедет на новую платформу – это будет удобный сайт самоучитель с четкой структурой и практическими заданиями. Но, конечно, там уже не будет общего чата и возможности задавать вопросы. Поэтому если вам важна поддержка преподавателя – сейчас самое время присоединиться.

Переход на платформу открывает перед нами массу возможностей: новые форматы, напоминания, быстрые обновления и т.д. Но если вы хотите учиться в уютной атмосфере Telegram канала с живым общением – добро пожаловать в третий поток.

Программа курса

P.S. На платформе курс тоже будет крутым – просто другим. А пока ловите последний шанс поучиться в "старом добром" формате!

#курс
👍9👏4🔥2
Как работает Nodelegatecall

Вчера закончились продажи курса, а значит мы возвращаемся в рабочую колею. И начнем нашу неделю с разговора о модификаторе nodelegatecall.

Модификатор nodelegatecall предотвращает отправку вызовов delegatecall в контракт. Сначала я покажу сам код, а затем мы обсудим, для чего это нужно.

Ниже упрощенный модификатор nodelegatecall, изначально созданный в Uniswap V3 для noDelegateCall:

contract NoDelegateCallExample {
address immutable private originalAddress;

constructor() {
originalAddress = address(this);
}

modifier noDelegateCall() {
require(address(this) == originalAddress, "no delegate call");
_;
}
}


Address(this) будет меняться в зависимости от среды выполнения, но originalAddress всегда будет адресом кода, использующего nodelegatecall. Поэтому если другой контракт выполнит delegatecall функции с модификатором noDelegateCall, то address(this) не будет равен originalAddress и транзакция откатится.

Крайне важно, чтобы original address был неизменяемой переменной, иначе контракт, выполняющий delegatecall, мог бы намеренно поместить в этот слот адрес контракта, использующего NoDelegateCall, и обойти оператор require.

Вот, например, как этот модификатор может быть протестирован:

contract NoDelegateCall {
address immutable private originalAddress;

constructor() {
originalAddress = address(this);
}

modifier noDelegateCall() {
require(address(this) == originalAddress, "no delegate call");
_;
}
}

contract A is NoDelegateCall {
uint256 public x;

function increment() noDelegateCall public {
x++;
}
}

contract B {
uint256 public x; // this variable does not increment

function tryDelegatecall(address a) external {
(bool ok, ) = a.delegatecall(
abi.encodeWithSignature("increment()")
);// ignore ok
}
}


Контракт B выполняет delegatecall для A, который использует модификатор nodelegatecall. Хотя транзакция B.tryDelegatecall не откатится, поскольку возвращаемое значение низкоуровневого вызова игнорируется, переменная хранения x не будет увеличена, поскольку транзакция внутри контекста delegatecall вернется.

Зачем вообще использовать nodelegatecall?

Uniswap V2 - один из самых популярных протоколов DeFi. Он столкнулся с конкуренцией со стороны других проектов, которые копировали его исходный код построчно и продвигали новый продукт как альтернативу Uniswap V2, а иногда и стимулировали пользователей, предоставляя airdrop.

Для того чтобы предотвратить это, команда Uniswap лицензировала Uniswap V3 через Business Source License - любой может скопировать код, но он не может использовать его в коммерческих целях до истечения срока действия лицензии в апреле 2023 года.

Однако если кто-то захочет сделать «копию» Uniswap V3, он может просто создать прокси-клона и указать ему на контракты Uniswap V3, а затем продавать этот проект, как альтернативу Uniswap V3. Модификатор nodelegatecall не позволяет этого сделать.

#nodelegatecall
👍7🤯3
Как работает ZKVM. Часть 1

В начале хотел бы сказать, что закрыл чат канал от комментариев, так как в последнее время заходит очень много ботов и спамеров. Ставить бота-модератора не хочу из-за наличия реклам и такой же необходимости чистить чат после них. Поэтому некоторое время будем без комментов.

А сейчас, перед праздниками, посмотрим на одну необычную тему о ZKVM.

Виртуальная машина с нулевыми знаниями (Zero-Knowledge Virtual Machine, ZKVM) - это виртуальная машина, которая может создать ZK-доказательство, подтверждающее, что она правильно выполнила набор машинных инструкций.

Это позволяет нам взять программу (набор операционных кодов), спецификацию виртуальной машины и доказать, что полученный результат является правильным. Верификатору не нужно повторно запускать программу, а только проверить сгенерированное ZK-доказательство - это позволяет сделать верификацию лаконичной.

Вопреки названию, ZKVM редко являются «нулевыми знаниями» в том смысле, что они хранят вычисления в тайне. Скорее, они используют алгоритмы ZK для получения краткого доказательства того, что программа выполнилась правильно на определенном входе, чтобы проверяющий мог перепроверить вычисления с экспоненциально меньшими затратами. Несмотря на то, что раскрытие входных данных программы необязательно, предотвращение случайных утечек данных и согласование приватного состояния несколькими сторонами - очень сложные инженерные задачи, которые до сих пор не решены и имеют ограничения по масштабированию.

ZKVM «вычисляет» каждый шаг в опкоде, а затем ограничивает правильность выполнения опкода. Ограничения должны быть разработаны таким образом, чтобы мы могли работать с произвольной, но корректной последовательностью опкодов.

Мы можем представить ZKVM как серию переходов из одного «состояния» в другое. Функция перехода в "состояние" принимает предыдущее состояние и текущий опкод, который должен быть выполнен, и генерирует новое состояние.

ZKVM реализует «функцию перехода состояния» и ограничения схемы, которые моделируют ее поведение. Обратите внимание, что «состояние» может включать в себя такие вещи, как «program counter» или другие учетные записи, необходимые для правильной работы VM.

В этой серии постов мы построим очень простую ZKVM, которая поддерживает только базовую арифметику, но может быть расширена для других операционных кодов. Представленная здесь VM имеет только стек и не имеет памяти или хранилища. В конце постов будут рекомендации по дальнейшему изучению ZKVM.

Простой ZKVM основанный на стеке

Мы построим простой стековый ZKVM с одним сигналом специального назначения, содержащим результат вычислений. VM получает серию опкодов и чисел, а затем выводит конечный результат на специальный сигнал, который мы вызываем.

Наш ZKVM имеет только следующие опкоды:

- PUSH (переносит первый аргумент в стек);
- ADD (извлекает два верхних элемента из стека и вставляет их сумму);
- MUL (выводит два верхних элемента из стека и выводит их произведение);
- NOP (нет операции, ничего не делать);

Для простоты все опкоды принимают один аргумент, но только PUSH использует этот аргумент. Остальные инструкции игнорируют аргумент.
Причина, по которой мы снабжаем аргументами опкоды, которые их не используют, заключается в том, что нам не нужно условно проверять наличие или отсутствие аргумента, основываясь на опкоде.

Здесь нет опкода STOP или RETURN (его замена будет объяснена в ближайшее время). VM принимает аргумент steps и возвращает значение, находящееся в нижней части стека после выполнения множества инструкций step.

P.S. В анимации выше приведен простой пример сложения двух чисел в этой архитектуре.

В Circom циклы не могут быть переменной длины, они всегда должны выполняться за фиксированное число итераций, так как сама базовая система ограничений ранга 1 (R1CS) должна иметь фиксированный размер. Аналогично, программы не могут быть переменного размера. Однако они должны иметь одинаковое количество опкодов, независимо от того, какая программа выполняется.
Чтобы запустить программу с меньшим количеством опкодов, чем фиксированное число, мы просто вставляем в нее NOP до тех пор, пока программа не достигнет максимального размера. Чтобы знать, когда «прекратить выполнение», пользователь должен предоставить вышеупомянутый аргумент steps, чтобы определить, когда будет возвращено значение в нижней части стека.

Несколько замечаний о нашей архитектуре:

- VM основана на стеке, как EVM, Java Virtual Machine или (для тех, кто знает) калькулятор Reverse Polish notation.

- Инструкций перехода нет, поэтому program counter только увеличивается.

- Все операционные коды принимают один аргумент, но ADD, MUL и NOP игнорируют переданный им аргумент. Это позволяет нам всегда увеличивать program counter на одну и ту же величину - нам не нужно обновлять его на 2 для PUSH, на 1 для ADD и так далее. Мы всегда сдвигаем счетчик на 2.

- Для того, чтобы прочитать аргумент PUSH, мы просто «смотрим вперед» на один индекс от program counter.

- Сложение и умножение выполняются с использованием модульной арифметики (по умолчанию в Circom). В качестве «размера слова» мы используем порядок поля по умолчанию в Circom - мы не пытаемся эмулировать виртуальные машины с традиционными размерами слов, такими как 64 или 256 бит. Эмуляция вычислений с битами фиксированного размера - тема следующей главы.

Вся статья тут - How a ZKVM Works.

#zkvm
👍10
Как работает ZKVM. Часть 2

Мы можем внести несколько ключевых изменений в наш стековый код из предыдущего поста, чтобы собрать ZKVM, соответствующий спецификации, описанной выше.

- Мы удалили опкод POP, поскольку он больше не нужен;
- Мы добавили опкоды ADD и MUL;

Вспомните, что предыдущие правила копирования предыдущего стека были следующими:

- A. Если sp равен 1 или больше, а столбец j находится на 1 индекс ниже sp, и текущая инструкция - PUSH или NOP, мы должны скопировать столбец j;

- B. Если sp равно 2 или больше, и столбец j находится на 2 индекса ниже sp, а текущая инструкция - POP, мы должны скопировать столбец j;

Правило A остается неизменным, а вот B нужно обновить следующим образом:

- B. Если sp равно 2 или больше, а столбец j находится на 3 индекса ниже sp, и текущая инструкция - ADD или MUL, мы должны скопировать столбец j;

Причина этого изменения в том, что предыдущая инструкция POP не изменяла второй по счету элемент стека, а только удаляла верхний. Однако ADD дважды открывает стек и выводит сумму. Аналогично, MUL дважды открывает стек и вставляет произведение.

Предыдущая реализация стека только записывала новые значения в указатель стека. Однако новая реализация может записывать сумму или произведение на два индекса ниже указателя стека. Например, 12 в стеке ниже станет 15 после сложения, а это место находится на два индекса ниже указателя стека:

Перед добавлением:
[12 , 3, sp] (sp = 3)


После сложения:
[15, sp] (sp = 2)


Здесь у нас есть 12 в качестве нижней части стека и sp, указывающий на пустое пространство над стеком.

Поэтому нам нужен сигнал, указывающий на то, что определенный столбец находится на два элемента ниже указателя стека.

Приведенный в оригинальной статье код в значительной степени заимствован из стека предыдущей главы, но в нем реализованы обновления, описанные в этой главе. А именно:

- Мы заменили NOP, PUSH и POP на NOP, PUSH, ADD и MUL. ADD и MUL уменьшают указатель стека на единицу, NOP сохраняет указатель стека неизменным, а PUSH увеличивает указатель стека на единицу и копирует свой аргумент в вершину стека.

Если хотите покопаться в самом коде, то лучше перейти на оригинальную статью, где он представлен в развернутом виде - https://www.rareskills.io/post/zkvm.

Также его можно перенести в редактор кода с нейронными сетями и изучить, разбивая на небольшие сниппеты.

#zkvm
👍3
Как работает ZKVM. Часть 3

Ну, и заключительный перевод статьи о ZKVM.

Разве не неэффективно иметь ограничения для каждого опкода, если мы используем только один?

В нашем ZKVM мы выполняем сложение и умножение для каждого элемента стека, хотя на самом деле используем только один из них. Это не имеет значения для таких легких операций, как сложение или умножение. Однако если бы у нас был опкод для такой сложной операции, как хеширование, это создало бы значительно больше ограничений; нам пришлось бы заполнять схему хеширования для каждого элемента в стеке, хотя хешировать нужно только вершину стека. Все это приведет к ненужным вычислениям и большим вычислительным затратам.

Мы можем повысить эффективность, используя Quin selector (или два) для определения того, какие элементы стека будут входом для опкода, но это все равно означает, что каждая итерация стека нуждается в ограничениях для хэша, даже если он их не использует.

Эта низкая эффективность ненужного повторения неиспользуемых ограничений является серьезным недостатком ванильного R1CS, который не позволяет условно использовать ограничения.

Решения для повышения эффективности

Два современных подхода, позволяющих значительно повысить эффективность, - это ограничения, основанные на таблицах поиска, и рекурсивные доказательства.

1. Таблица поиска - это схема арифметизации, в которой только те ограничения, которые действительно используются, являются частью таблицы, а затем ZK-доказательство доказывает, что оно использовало правильную запись из таблицы для каждой инструкции.

2. Рекурсивное доказательство создает отдельное ZK-доказательство для каждой инструкции, а затем объединяет его с другим ZK-доказательством, которое проверяет правильность входных доказательств. Учтите, что алгоритм верификации в ZK сам по себе может быть смоделирован с помощью арифметической схемы.

#zkvm
👍4
Вышла новая версия Solidity 0.8.30

Команда Solidity представила версию 0.8.30 компилятора. Этот релиз — техническое обновление, связанное с предстоящим обновлением сети Ethereum Pectra, которое вышло на прошлой неделе. Основное изменение — смена EVM-версии по умолчанию с Cancun на Prague.

Pectra — это масштабное обновление Ethereum, следующее за Dencun, которое вносит изменения как в execution layer, так и в consensus layer сети. Рассмотрим ключевые EIP, влияющие на Solidity.

EIP-7623: Увеличение стоимости calldata

EIP-7623 повышает стоимость calldata для транзакций, которые в основном отправляют данные. Это компенсирует увеличение пропускной способности из-за EIP-7691, уменьшая максимальный размер блока.

Изменение может повлиять на оптимизацию констант в компиляторе. Например, значение 2**256 - 1 можно закодировать как PUSH32 (3 газа, 33 байта) или PUSH0 NOT (5 газа, 2 байта). Оптимизатор выбирает вариант, исходя из стоимости calldata, но из-за нелинейного роста затрат точный расчет усложняется.

Команда Solidity не стала вносить изменения в алгоритмы оптимизации, так как учесть новый расчет стоимости на уровне отдельных opcode практически невозможно. Вместо этого рекомендуется настраивать параметры оптимизации вручную, например, через --optimizer-runs.

EIP-7702: Делегирование EOA контракту

EIP-7702 добавляет новый тип транзакции, позволяющий EOA временно делегировать управление контракту. Это важный шаг к полной account abstraction.

В версии 0.8.30 нет изменений, связанных с этим EIP, но предыдущий релиз (0.8.29) добавил контроль над storage layout, чтобы несколько пользователей могли безопасно использовать хранилище одного EOA.

EIP-2537: Прекомпиляция для операций с BLS12-381


EIP-2537 добавляет прекомпиляцию для верификации BLS-подписей на блокчейне. В отличие от ECDSA, BLS-подписи поддерживают агрегацию, что делает их полезными для консенсуса.

Пока Solidity не добавляет встроенную поддержку BLS, так как вызовы прекомпилированных контрактов можно реализовать через внешние функции. Команда рассматривает возможность включения этой функциональности в стандартную библиотеку в будущем.

Исправления и улучшения

1. Установлена EVM-версия по умолчанию prague.

2. NatSpec теперь фиксирует документацию enum в AST.

3. Исправлены ошибки в SMTChecker, включая ложные отчеты о постоянных условиях и внутренние ошибки компилятора.

Обновляйтесь и тестируйте свои контракты с выходом Pectra!

#solidity
👍113
Погружение в EIP-7702. Часть 1

Уже столько всего слышал про обновление Pectra и данный новый стандарт, но все ждал, когда выйдет чуть больше информации с примерами и нюансами использования. Наконец, хочу сделать небольшой цикл постов на основе разных статей, где мы погрузимся в эту тему и разберемся, что к чему.

EIP-7702 - это важное обновление Ethereum, которое позволит аккаунтам, принадлежащим внешним пользователям (Externally Owned Accounts, EOA), напрямую выполнять код смарт-контрактов. Это изменение позволяет EOA получить функциональные возможности смарт-контрактов, что способствует продвижению Ethereum к полной абстракции аккаунтов (account abstraction).

Как обновление Pectra с помощью EIP-7702 повлияет на Account Abstraction Roadmap

Долгосрочная цель Ethereum - превратить каждый аккаунт, принадлежащий внешнему владельцу (Externally Owned Account, EOA), в смарт аккаунт. Хотя Account Abstraction все еще является хоть и не далекой, но все же перспективой, хард форк Pectra ознаменовал собой ключевой шаг вперед, представив EIP-7702. Это обновление позволяет любому EOA запускать код смарт-контракта непосредственно на своем адресе, эффективно расширяя его функциональность за счет возможностей, традиционно доступных только смарт-контрактам.

EIP-7702: Расширение EOA с помощью функций смарт-контракта

EOA и смарт-контракты исторически различались: EOA могут инициировать транзакции, но не могут выполнять код, в то время как смарт-контракты могут выполнять код при вызовах, но не могут начинать транзакции. EIP-7702 устраняет этот разрыв, позволяя EOA выполнять код, стирая границы между ними и смарт-контрактами. Это расширение открывает новые возможности для пользователей, позволяя им пользоваться функциями, подобными смарт-контрактам, без необходимости переходить на полноценные смарт-контракты.

Благодаря EIP-7702 EOA теперь могут хранить адрес, называемый «delegation designator», который указывает на смарт-контракт. Когда транзакция отправляется на EOA, он может выполнить код по этому назначенному адресу, как если бы он был его собственным, подобно тому, как работает «delegate call» в смарт-контрактах.

Если делегированный адрес включает функции смарт-аккаунта, то EOA может функционировать как смарт-аккаунт. Это означает, что он может поддерживать подписание транзакций несколькими владельцами, устанавливать пороговые значения, использовать passkey в качестве подписывающих лиц, а также добавлять различные модули для расширения своих возможностей.

Ключевое отличие от обычного смарт-аккаунта заключается в том, что приватный ключ EOA сохраняет полный контроль. Он может подписывать как транзакции в сети, так и сообщения вне ее, поэтому безопасность этого приватного ключа остается крайне важной. Даже при наличии функций смарт-аккаунта защита приватного ключа необходима для предотвращения несанкционированного доступа.

В конечном итоге это позволит пользователям интегрировать свои EOA в кошельки смарт-аккаунтов, такие как Safe Wallet, предоставляя им доступ к полному набору функций аккаунтов, с которыми они уже знакомы. Это означает, что теперь EOA могут воспользоваться преимуществами повышенной безопасности, удобства и гибкости без необходимости полностью переходить на новый кошелек.

Операция по добавлению «delegation designator» вводит новый тип транзакции, не поддерживаемый автоматически кошельками. Этот новый тип необходим для того, чтобы пользователи не могли непреднамеренно подписать ее и делегировать контроль над своей EOA. Кошельки должны будут реализовать поддержку этой транзакции, отображая специальный интерфейс, который четко объясняет последствия - аналогично интерфейсу, используемому при экспорте закрытого ключа. Из-за значительных рисков безопасности эта транзакция, скорее всего, будет осуществляться доверенными кошельками, а не децентрализованными приложениями (dapp).
23👍1👌1
Транзакция включает в себя такие данные, как nonce EOA, адрес delegation designator и идентификатор сети. Это влияет на ее кросс-сетевую функциональность. Пользователи могут включить идентификатор конкретной сети, ограничив действие транзакции только в ней.

В качестве альтернативы они могут установить идентификатор сети на ноль, что сделает транзакцию действительной для нескольких. Однако для того, чтобы это сработало, nonce EOA должен совпадать в разных сетях. Если nonce отличается - из-за того, что EOA проводит разное количество транзакций в разных блокчейнах, - транзакция будет успешной только в одной из них. Это означает, что EOA с нулевым nonce может создать транзакцию, действительную на всех сетях. И наоборот, EOA с историей транзакций в нескольких блокчейнах придется генерировать отдельные транзакции, каждая из которых будет иметь соответствующий nonce для соответствующей сети.

#eip7702
1👍32
Погружение в EIP-7702. Часть 2

Сегодня обозначим преимущества и недостатки EIP-7702.

EIP-7702 привносит функции Smart Account в EOA, в первую очередь позволяя им получить доступ к преимуществам Account Abstraction (ERC-4337), которые ранее были ограничены Smart Accounts. Основные преимущества включают:

1. Спонсируемые транзакции: Теперь EOA могут воспользоваться преимуществами спонсированных транзакций, при которых платежная система покрывает газовые сборы. Это позволяет EOA выполнять транзакции в сетях, где у них нет средств на газ, что упрощает использование новых сетей. Протоколы также могут покрывать расходы на газ для своих пользователей (например, они могут подать заявку на Safe Gas Station, что позволит Safe произвести оплату).

2. Пакетные транзакции (Batched Transactions): EOA могут отправлять несколько транзакций с одной подписью, что особенно полезно для межсетевых операций или транзакций, требующих объединения, таких как депозиты.

3. Passkeys: Пользователи могут легко подписывать транзакции с помощью ключей доступа, обеспечивая более быструю и надежную аутентификацию, что повышает удобство и безопасность.

4. Ключи сеансов: EOA могут «входить» в dapp и авторизировать транзакции в течение определенного периода времени (например, 24 часа), снижая необходимость для пользователей вручную подписывать каждую транзакцию. Эта функция идеально подходит для таких сценариев, как усреднение затрат в долларах или ограничение прав доступа к определенным активам или функциям, что повышает удобство использования и безопасность.

5. Возможность отзыва: Пользователи сохраняют полный контроль над своими EOA, имея возможность в любой момент отозвать или изменить назначение вызова.

6. Восстановление активов: Если закрытый ключ утерян, но функции восстановления настроены с помощью EIP-7702, пользователи могут восстановить активы, хранящиеся в учетной записи, что добавляет другой уровень безопасности.

7. Улучшенный межсетевой пользовательский интерфейс: теперь EOA, оснащенные функциями «умного аккаунта», могут использовать chain abstraction. Это позволяет осуществлять бесшовные транзакции в нескольких сетях без необходимости вручную переключаться между ними в кошельке или беспокоиться о том, где развернут протокол.

8. Бесшовная интеграция со смарт-кошельками: Пользователи смогут встраивать свои EOA в кошельки Smart Account, такие как Safe Wallet, что позволит им пользоваться полным набором функций Smart Account, к которым они уже привыкли. Такая интеграция повышает удобство использования и безопасность, сохраняя доступ к существующим активам без необходимости перехода на совершенно новый кошелек.

EIP-7702 значительно улучшает EOA, делая их более универсальными и удобными в использовании, с функциями, традиционно предназначенными для смарт-аккаунтов.

А теперь о недостатках.

Несмотря на то, что EIP-7702 является значительным шагом на пути перехода от EOA к Smart Accounts, он не является полной реализацией account abstraction, а также не полностью преобразует EOAs в Smart Accounts. С точки зрения абстракции учетной записи он имеет ряд ограничений:

1. Закрытый ключ EOA сохраняет полный контроль над учетной записью, действуя как черный ход, который может отменить функции Smart Account. Поэтому очень важно обеспечить защиту ключа, так как любой злоумышленник, получивший доступ, может получить полный контроль и украсть все активы.

2. В случаях, когда смарт-аккаунт с несколькими подписями создается на основе EOA, другие владельцы должны полностью доверять владельцу оригинальной EOA. Поскольку закрытый ключ EOA может уничтожить смарт-аккаунт в ходе одной транзакции, это подрывает безопасность и доверие, необходимые для мультисиговых систем, и делает нецелесообразным использование перенесенного EOA несколькими владельцами.

3. Если закрытый ключ утерян или скомпрометирован, восстановить полный контроль над EOA не представляется возможным. Единственным решением будет замена закрытого ключа, что может оказаться сложной задачей и не дает прямого механизма восстановления.
🔥5
4. Для будущей защиты от угроз, связанных с квантовыми вычислениями, пользователям со временем придется перейти на полностью квантоустойчивые смарт-аккаунты. Смарт-аккаунты с расширенными функциональными возможностями все еще уязвимы для потенциальных алгоритмов, работающих на квантовых технологиях, которые могут скомпрометировать их закрытые ключи. Это подчеркивает необходимость постепенного перехода или экстренного обновления для обеспечения безопасности учетных записей в постквантовом мире.

5. Неспособность блокировать ресурсы или выступать в качестве Escrow: поскольку приватный ключ всегда имеет право передавать средства, смарт-контракты, построенные на EOA, не могут эффективно выступать в качестве escrow или надежно блокировать средства. Этот нюанс ограничивает использование функций смарт-аккаунтов, где требуется блокировка ресурсов.

Эти недостатки подчеркивают переходный характер EIP-7702, предлагающего дополнительные преимущества, но не обеспечивающего полной абстракции счета.

#eip7702
👍4
Погружение в EIP-7702. Часть 3

Полный account abstraction предполагает, что каждый аккаунт в Ethereum будет представлять собой смарт-аккаунт, что приведет к существенным улучшениям как в плане безопасности, так и в плане удобства использования:

1. Больше схем подписи: В настоящее время EOA поддерживают только один тип подписи. С полной account abstraction станет возможным использование множества схем подписи, включая варианты, работающие со смартфонами и другими устройствами (например, passkeys). Это значительно повысит безопасность и удобство использования.

2. Опции восстановления по умолчанию: Смарт-аккаунты могли бы предлагать встроенные функции восстановления по умолчанию, или же пользователи могли бы легко отказаться от них. Это значительно снизит риск потери средств из-за ошибок или утери приватных ключей.

3. Спонсируемые транзакции: Каждый смарт-аккаунт будет иметь возможность подписывать спонсируемые транзакции. Это избавит пользователей от необходимости беспокоиться о комиссиях за газ и управлении цепочками, позволяя им сосредоточиться исключительно на удобстве и прибыльности dapp, с которой они взаимодействуют.

Пакетные транзакции и сеансовые ключи: Смарт-аккаунты могут «входить» в dapps, обеспечивая пользовательский опыт, схожий с централизованными приложениями. Это позволит быстро и без проблем осуществлять такие действия, как торговля и игры, без необходимости постоянного одобрения транзакций.

Шаги по достижению полной account abstraction

Для того, чтобы полностью реализовать АА, необходимо осуществить несколько ключевых изменений:

1. Интеграция ядра: АА должна быть полностью встроена в основной протокол Ethereum. В то время как ERC-4337 в настоящее время работает на прикладном уровне, усовершенствования на уровне протокола, такие как RIP-7560, сделают транзакции более газоэффективными и объединят все транзакции под одним мемпулом, устранив необходимость в отдельном мемпуле для операций ERC-4337.

2. Смарт-аккаунты по умолчанию: Все новые учетные записи Ethereum по умолчанию должны быть смарт-аккаунтами, при этом новые EOA создаваться не будут. Новые пользователи с самого начала смогут воспользоваться расширенными возможностями смарт-аккаунтов.

3. Перенос EOA на смарт-аккаунты: Существующие EOA необходимо преобразовать в Smart Accounts. Это особенно важно для пользователей, которые хотят сохранить свои оригинальные адреса из-за ценных непередаваемых активов, таких как soul-bound tokens. EIP-7702 играет решающую роль в этом переходе, но для удаления доступа к закрытому ключу EOA необходимы дополнительные меры. Ключевую роль здесь играет EIP-3607, который отменяет доступ к закрытому ключу, если аккаунт содержит код.

Проверка подписи

Смарт-аккаунты уже могут проверять подписи с помощью EIP-1271. Для завершения миграции необходимо обновить процессы проверки подписи, чтобы проверить, является ли подписант EOA или Смарт-аккаунтом. Если это Смарт-аккаунт, то подписи на основе закрытых ключей больше не должны валидироваться.

Соображения по поводу внесетевой проверки

Проверка подписи вне сети также должна учитывать возможность того, что учетная запись может быть EOA в одной сети, но Smart Account в другой. Верификаторы подписей должны быть ориентированы на конкретную сеть, обеспечивая правильную проверку подписей в зависимости от сети, из которой они были получены.

Такой оптимизированный путь к полной account abstraction в конечном итоге позволит создать бесшовную, безопасную и высокомасштабируемую экосистему Ethereum, в которой каждый аккаунт сможет воспользоваться расширенными возможностями смарт-аккаунтов.

#eip7702
👍3
Погружение в EIP-7702. Часть 4

Итак, как мы знаем, EIP-7702 представляет новый тип транзакции 0x04 в обновлении Pectra для Ethereum, который позволяет аккаунтами, принадлежащим внешним пользователям (EOA), выполнять временные функции смарт-контракта. Это усовершенствование Account Abstraction устраняет разрыв между EOA и смарт-контрактами, позволяя реализовать такие ключевые функции, как пакетные транзакции, спонсируемые платежи и контролируемое делегирование доступа.

EIP-7702 теперь активен в основной сети Ethereum, а также в тестовых сетях, таких как Sepolia, как часть обновления Pectra. Разработчики могут протестировать EIP-7702 в локальных средах Foundry - либо в свежей локальной сети, либо с помощью форка mainnet.

Транзакции EIP-7702


В то время как обычные транзакции Ethereum либо переводят средства, либо взаимодействуют со смарт-контрактами, новый тип транзакций 0x04 позволяет EOA выполнять код напрямую.

Благодаря новому стандарту EOA могут выполнять логику смарт-контракта непосредственно со своего собственного адреса, что делает возможным:

1. Пакетные транзакции: Объединять несколько действий в одну атомарную транзакцию (одобрение токенов, обмен, передача).
2. Делегирование ограниченного доступа: Предоставление временных, ограниченных полномочий без раскрытия ключей.
3. Спонсорство: Позволяет третьей стороне (например, paymaster) покрывать комиссию за газ для ваших транзакций.
4. Восстановление кошелька: Реализуйте механизм восстановления при потере приватного ключа.

Подписание авторизации

Пользователь (EOA) подписывает сообщение авторизации, которое включает в себя идентификатор цепочки, nonce, адрес делегирования и части подписи (y_parity, r, s). В результате генерируется подписанная авторизация, гарантирующая, что только утвержденный контракт может выполнять транзакции, и защищающая от атак повторного воспроизведения.

Для каждого разрешенного адреса делегирования пользователь (EOA) хранит обозначение делегирования - указатель на контракт реализации, которому EOA будет делегировать полномочия. Когда пользователь (или спонсор) выполняет транзакцию EIP-7702, он загружает и запускает код с адреса, указанного этим указателем.

Конструкция транзакции

В типичной транзакции Ethereum, если вы хотите вызвать функцию смарт-контракта, вы устанавливаете в поле to адрес этого контракта и включаете соответствующие данные для вызова его функции. В EIP-7702 вы устанавливаете в поле to адрес EOA и включаете данные для вызова функции контракта реализации в подписанное сообщение авторизации.

Анатомия транзакции EIP-7702

Приведенный ниже фрагмент кода демонстрирует, как с помощью клиента кошелька Viem создать пакетную транзакцию для смарт-аккаунта EIP-7702.

1. Он генерирует авторизационную подпись для определенного контракта.

2. Затем создается транзакция, в которой в поле to устанавливается собственный адрес смарт-счета.

3. Поле данных создается путем кодирования вызова функции execute с помощью массива из двух объектов call. Функция execute должна быть определена в контракте реализации и обрабатывать логику пакетной транзакции.

4. Наконец, транзакция включает подписанную авторизацию в authorizationList, что позволяет смарт-аккаунту делегировать выполнение контракту реализации.

Если другой кошелек (спонсор) захочет выполнить эту транзакцию (спонсируемая транзакция), он может использовать ту же подпись авторизации, чтобы делегировать выполнение контракту реализации.

Примечание: Контракты должны быть разработаны для обработки пакетных транзакций и других возможностей, предусмотренных EIP-7702. Кроме того, они должны включать механизмы защиты.

#eip7702
👍61