Что такое EVM?
EVM — это среда выполнения для блокчейна Ethereum. Позволяет запускать код смарт-контракта путем компиляции в байт-код EVM.
Основы: Solidity → Байт-код → Opcode
Как вы знаете, код Solidity должен быть скомпилирован в байт-код перед развертыванием в сети Ethereum. Этот байт-код соответствует серии инструкций кода операции, которые интерпретирует EVM.
Исходный код: файл, написанный на языке программирования, таком как Java, Solidity.
Байт-код: скомпилирован из исходного кода и запущен на виртуальной машине, такой как JVM, EVM.
Машинный код: код, который может прочитать только операционная система. Байт-код преобразуется в машинный код и, наконец, выполняется.
Байт-код
![](https://habrastorage.org/getpro/habr/upload_files/89a/b05/5b0/89ab055b07d3d2b8845835a20b0e99ee.png)
Чтобы эффективно хранить коды операций, они кодируются в байт-код. Каждому коду операции выделяется байт (например, STOP - 0x00). Давайте посмотрим на следующий байт-код: 0x6001600101
Во время выполнения байт-код разбивается на байты (1 байт равен 2 шестнадцатеричным символам). Байты в диапазоне 0x60–0x7f (PUSH1-PUSH32) обрабатываются по-другому, потому что они включают данные push (которые необходимо присоединить к коду операции, а не рассматривать как отдельный код операции).
Первая инструкция - 0x60, которая переводится в PUSH1. Следовательно, мы знаем, что длина push-данных составляет 1 байт, и добавляем следующий байт в стек. Теперь в стеке 1 элемент, и мы можем перейти к следующей инструкции. Поскольку мы знаем, что 0x01 является частью инструкции PUSH, следующая инструкция, которую нам нужно выполнить, - это еще одна инструкция 0x60 (PUSH1) вместе с теми же данными. Теперь в стопке 2 одинаковых элемента. Последняя инструкция - 0x01, что переводится как ADD. Эта инструкция берет 2 элемента из стека и помещает сумму этих элементов в стек. Теперь в стеке один элемент: 0x02.
Коды операций
![](https://habrastorage.org/getpro/habr/upload_files/55a/3d3/12c/55a3d312c67d40d941c4e03a2e807c5c.png)
Можно разделить все коды операций на следующие категории:
Коды операций управления стеком (POP, PUSH, DUP, SWAP);
Арифметические операции / сравнение / побитовые коды операций (ADD, SUB, GT, LT, AND, OR);
Коды операций окружающей среды (CALLER, CALLVALUE, NUMBER);
Коды операций, управляющие памятью (MLOAD, MSTORE, MSTORE8, MSIZE);
Коды операций управления памятью (SLOAD, SSTORE);
Коды операций, относящиеся к счетчику программ (JUMP, JUMPI, PC, JUMPDEST);
Коды операций остановки (STOP, RETURN, REVERT, INVALID, SELFDESTRUCT).
Архитектура EVM
![](https://habrastorage.org/getpro/habr/upload_files/f20/21b/664/f2021b6645994b751473e04c17d8ec6e.png)
EVM использует архитектуру на основе стека. Размер слова (то есть размер элемента данных в стеке) составляет 256 бит (32 байта). Это сделано для облегчения выполнения 256-битных вычислений Keccak-хэша и эллиптических кривых. Его модель памяти основана на байтовых массивах с адресной адресацией. Максимальная глубина стека - 1024. EVM также имеет независимую модель хранения; она похожа на память, но представляет собой не массив байтов, а массив слов, основанный на адресации по словам. Хранилище - это постоянное хранилище ключей и значений, которое поддерживается как часть состояния системы (постоянное хранилище в дереве Меркла). Все данные в памяти и хранилище будут инициализированы до 0. EVM не является стандартной структурой фон Неймана. Программный код хранится в независимом виртуальном ПЗУ, которое может взаимодействовать только с помощью определенных инструкций, а не в общедоступной памяти или хранилище.
Полезные ссылки: https://www.evm.codes/, https://ethervm.io/
Зачем нужен газ?
![](https://habrastorage.org/getpro/habr/upload_files/282/280/895/2822808957a3636ec1d4c5197dd32fa5.png)
Плата за газ помогает поддерживать безопасность сети Ethereum. Требуя плату за каждое вычисление, выполняемое в сети, мы не позволяем злоумышленникам рассылать спам в сети. Чтобы избежать случайных или враждебных бесконечных циклов или других вычислительных потерь в коде, каждая транзакция должна устанавливать ограничение на количество вычислительных шагов выполнения кода, которое она может использовать. Основная единица вычислений - «газ».
Хотя транзакция включает лимит, любой газ, не использованный в транзакции, возвращается пользователю (т.е. возвращается max fee - (base fee + tip)).
Виды учётных записей Ethereum
![](https://habrastorage.org/getpro/habr/upload_files/7e3/413/5f0/7e34135f00c1ab7b5caec5cb35ba90a7.png)
Externally-owned — контролируется кем-либо, у кого есть private key.
Contract — смарт-контракт, развернутый в сети, управляемый кодом.
Оба типа учетных записей имеют возможность:
Получать, хранить и отправлять ETH и токены;
Взаимодействовать с развернутыми смарт-контрактами.
Ключевые отличия
Externally-owned:
Создание учетной записи ничего не стоит;
Может инициировать транзакции;
Транзакции между Externally-owned могут быть только переводы ETH / токенов.
Contract:
Создание контракта требует затрат, потому что используется сетевое хранилище;
Может отправлять транзакции только в ответ на полученные транзакции;
Транзакции от Externally-owned учётной записи в Contract учетную запись могут запускать код, который может выполнять множество различных действий, таких как передача токенов или даже создание нового контракта.
Создание учётной записи
![](https://habrastorage.org/getpro/habr/upload_files/8a5/95c/f57/8a595cf577efd96af1a391d252ccceed.png)
![](https://habrastorage.org/getpro/habr/upload_files/a38/a47/01b/a38a4701b48a5c358e99c2d99018ae27.png)
EVM обрабатывает адреса длиной 160 бит.
Учетная запись состоит из криптографической пары ключей: public и private. Public key генерируется из private key с помощью алгоритма ECDSA.
Публичный адрес Externally-owned учетной записи формируется следующим образом — берутся последние 20 байтов от Keccak-256(public key) и добавляется 0x в начало.
Адрес Contract обычно указывается при развертывании контракта в блокчейне Ethereum. Адрес формируется из Externally-owned адреса создателя и количества транзакций, отправленных с этого адреса («nonce»). Последние 20 байтов от Keccak-256(RLP(Externall-owned; nonce)).
Про RLP: https://eth.wiki/fundamentals/rlp
Скрины формул из Ethereum Yellow Paper: https://ethereum.github.io/yellowpaper/paper.pdf
Что входит в каждый тип учётной записи
![](https://habrastorage.org/getpro/habr/upload_files/9f8/45a/76f/9f845a76f1f27fbb541317fc632253c9.png)
Каждая учетная запись состоит из balance, nonce, bytecode и stored data (storage). Однако между двумя типами учетных записей есть некоторые различия. Например, у External-owned поля bytecode и storage пусты, в то время как Contract хранит свой байт-код и корневой хэш Меркла всего дерева состояний. Более того, в то время как External-owned имеют соответствующий private key, Contract - нет. Действия Contract учетных записей контролируются кодом.
JekaMas
Позволю поправить понятия и убрать маркетин
EVM — это FSM, он же конечный автомат. Небольшая стэковая машинка на 1000-2000 строк кода.
Газ нужен для решения проблемы остановки и, главное, чтобы поддерживать курс эфира.
Контракт solidity - хранимая процедура базы данных.