Что такое 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.
Коды операций

Можно разделить все коды операций на следующие категории:
Коды операций управления стеком (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

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 — смарт-контракт, развернутый в сети, управляемый кодом.
Оба типа учетных записей имеют возможность:
Получать, хранить и отправлять ETH и токены;
Взаимодействовать с развернутыми смарт-контрактами.
Ключевые отличия
Externally-owned:
Создание учетной записи ничего не стоит;
Может инициировать транзакции;
Транзакции между Externally-owned могут быть только переводы ETH / токенов.
Contract:
Создание контракта требует затрат, потому что используется сетевое хранилище;
Может отправлять транзакции только в ответ на полученные транзакции;
Транзакции от 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 учетных записей контролируются кодом.