Что такое EVM?

EVM — это среда выполнения для блокчейна Ethereum. Позволяет запускать код смарт-контракта путем компиляции в байт-код EVM.

Основы: Solidity → Байт-код → Opcode

Как вы знаете, код Solidity должен быть скомпилирован в байт-код перед развертыванием в сети Ethereum. Этот байт-код соответствует серии инструкций кода операции, которые интерпретирует EVM.

Исходный код: файл, написанный на языке программирования, таком как Java, Solidity.

Байт-код: скомпилирован из исходного кода и запущен на виртуальной машине, такой как JVM, EVM.

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

Байт-код

Чтобы эффективно хранить коды операций, они кодируются в байт-код. Каждому коду операции выделяется байт (например, STOP - 0x00). Давайте посмотрим на следующий байт-код: 0x6001600101

Во время выполнения байт-код разбивается на байты (1 байт равен 2 шестнадцатеричным символам). Байты в диапазоне 0x60–0x7f (PUSH1-PUSH32) обрабатываются по-другому, потому что они включают данные push (которые необходимо присоединить к коду операции, а не рассматривать как отдельный код операции).

Первая инструкция - 0x60, которая переводится в PUSH1. Следовательно, мы знаем, что длина push-данных составляет 1 байт, и добавляем следующий байт в стек. Теперь в стеке 1 элемент, и мы можем перейти к следующей инструкции. Поскольку мы знаем, что 0x01 является частью инструкции PUSH, следующая инструкция, которую нам нужно выполнить, - это еще одна инструкция 0x60 (PUSH1) вместе с теми же данными. Теперь в стопке 2 одинаковых элемента. Последняя инструкция - 0x01, что переводится как ADD. Эта инструкция берет 2 элемента из стека и помещает сумму этих элементов в стек. Теперь в стеке один элемент: 0x02.

Коды операций

Можно разделить все коды операций на следующие категории:

  1. Коды операций управления стеком (POP, PUSH, DUP, SWAP);

  2. Арифметические операции / сравнение / побитовые коды операций (ADD, SUB, GT, LT, AND, OR);

  3. Коды операций окружающей с��еды (CALLER, CALLVALUE, NUMBER);

  4. Коды операций, управляющие памятью (MLOAD, MSTORE, MSTORE8, MSIZE);

  5. Коды операций управления памятью (SLOAD, SSTORE);

  6. Коды операций, относящиеся к счетчику программ (JUMP, JUMPI, PC, JUMPDEST);

  7. Коды операций остановки (STOP, RETURN, REVERT, INVALID, SELFDESTRUCT).

Архитектура EVM

EVM использует архитектуру на основе стека. Размер слова (то есть размер элемента данных в стеке) составляет 256 бит (32 байта). Это сделано для облегчения выполнения 256-битных вычислений Keccak-хэша и эллиптических кривых. Его модель памяти основана на байтовых массивах с адресной адресацией. Максимальная глубина стека - 1024. EVM также имеет независимую модель хранения; она похожа на память, но представляет собой не массив байтов, а массив слов, основанный на адресации по словам. Хранилище - это постоянное хранилище ключей и значений, которое поддерживается как часть состояния системы (постоянное хранилище в дереве Меркла). Все данные в памяти и хранилище будут инициализированы до 0. EVM не является стандартной структурой фон Неймана. Программный код хранится в независимом виртуальном ПЗУ, которое может взаимодействовать только с помощью определенных инструкций, а не в общедоступной памяти или хранилище.

Полезные ссылки: https://www.evm.codes/, https://ethervm.io/

Зачем нужен газ?

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

Хотя транзакция включает лимит, любой газ, не использованный в транзакции, возвращается пользователю (т.е. возвращается max fee -  (base fee + tip)). 

Виды учётных записей Ethereum

Externally-owned — контролируется кем-либо, у кого есть private key.

Contract — смарт-контракт, развернутый в сети, управляемый кодом.

 Оба типа учетных записей имеют возможность:

  1. Получать, хранить и отправлять ETH и токены;

  2. Взаимодействовать с развернутыми смарт-контрактами.

Ключевые отличия

 Externally-owned:

  1. Создание учетной записи ничего не стоит;

  2. Может инициировать транзакции;

  3. Транзакции между Externally-owned могут быть только переводы ETH / токенов.

 Contract:

  1. Создание контракта требует затрат, потому что используется сетевое хранилище;

  2. Может отправлять транзакции только в ответ на полученные транзакции;

  3. Транзакции от Externally-owned учётной записи в Contract учетную запись могут запускать код, который может выполнять множество различных действий, таких как передача ��окенов или даже создание нового контракта. 

Создание учётной записи

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

Что входит в каждый тип учётной записи

Каждая учетная запись состоит из balance, nonce, bytecode и stored data (storage). Однако между двумя типами учетных записей есть некоторые различия. Например, у External-owned поля bytecode и storage пусты, в то время как Contract хранит свой байт-код и корневой хэш Меркла всего дерева состояний. Более того, в то время как External-owned имеют соответствующий private key, Contract - нет. Действия Contract учетных записей контролируются кодом.