[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-3-ponimanie-gaza-pochemu-kontrakt-stoit-stolko":3},{"article":4,"author":54},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":34,"related_articles":35},"d0000000-0000-0000-0000-000000000203","a0000000-0000-0000-0000-000000000012","Deep EVM #3: Понимание газа — почему ваш контракт стоит столько","deep-evm-3-ponimanie-gaza-pochemu-kontrakt-stoit-stolko","Детальный анализ модели газа Ethereum: как рассчитывается стоимость транзакции, почему SSTORE так дорог, и конкретные паттерны оптимизации, экономящие тысячи газа.","## Газ: экономическая модель EVM\n\nГаз в Ethereum — это не просто техническое ограничение. Это экономическая система, которая ценит вычислительные ресурсы, предотвращает злоупотребления и определяет, сколько стоит ваш контракт для пользователей. Каждый опкод, каждое обращение к памяти, каждая запись в хранилище — всё измеряется в газе.\n\nПонимание газа на глубоком уровне — это разница между контрактом, который стоит $2 за транзакцию, и контрактом, который стоит $0.20. В мире DeFi и MEV это разница между прибыльным и убыточным бизнесом.\n\n## Анатомия стоимости транзакции\n\nСтоимость транзакции в Ethereum складывается из нескольких компонентов:\n\n### 1. Внутренний газ (Intrinsic Gas)\n\nКаждая транзакция начинается с базовой стоимости:\n\n| Компонент | Стоимость |\n|-----------|----------|\n| Базовая стоимость транзакции | 21000 газа |\n| Ненулевой байт calldata | 16 газа |\n| Нулевой байт calldata | 4 газа |\n| Создание контракта (CREATE) | 32000 газа |\n| Список доступа: адрес | 2400 газа |\n| Список доступа: слот хранилища | 1900 газа |\n\nДля простого перевода ETH (нет calldata) это ровно 21000 газа. Для вызова `transfer(address,uint256)` на ERC-20 — 21000 + стоимость calldata + стоимость выполнения.\n\nCalldata для `transfer`:\n```\n\u002F\u002F 4 байта селектора + 32 байта адреса + 32 байта суммы = 68 байт\n\u002F\u002F Типичная стоимость: ~16 * 40 (ненулевых) + 4 * 28 (нулевых) = 752 газа\n```\n\n### 2. Стоимость выполнения\n\nЭто сумма газа всех выполненных опкодов. Для типичного ERC-20 transfer:\n\n```\n\u002F\u002F Примерная разбивка стоимости ERC-20 transfer:\n\u002F\u002F Диспетчеризация функций:     ~100 газа\n\u002F\u002F Загрузка баланса отправителя: ~2100 газа (холодный SLOAD)\n\u002F\u002F Проверка достаточности:       ~10 газа\n\u002F\u002F Обновление баланса отправителя: ~2900 газа (тёплый SSTORE, ненулевое->ненулевое)\n\u002F\u002F Загрузка баланса получателя:  ~2100 газа (холодный SLOAD)\n\u002F\u002F Обновление баланса получателя: ~20000 или 2900 газа (зависит от нулевого\u002Fненулевого)\n\u002F\u002F Эмиссия события Transfer:     ~1500 газа (LOG3 + данные)\n\u002F\u002F Возврат значения:              ~50 газа\n\u002F\u002F Итого: ~29000-51000 газа\n```\n\nОбратите внимание на огромную разницу: если получатель уже имел баланс (ненулевое->ненулевое SSTORE: 2900), транзакция на ~17000 газа дешевле, чем если получатель новый (нулевое->ненулевое: 20000).\n\n### 3. EIP-1559: базовая ставка и приоритет\n\nС обновления London (август 2021) стоимость газа определяется двумя компонентами:\n\n```\nобщая стоимость = газ_использовано * (базовая_ставка + приоритетная_ставка)\n```\n\n- **Базовая ставка (base fee)** — алгоритмически определяется протоколом. Увеличивается, когда блоки заполнены более чем наполовину; уменьшается, когда менее. Сжигается полностью.\n- **Приоритетная ставка (priority fee \u002F tip)** — платёж валидатору за включение транзакции. В периоды низкой нагрузки ~1-2 gwei; при высокой ~20-100+ gwei.\n\n## Почему SSTORE так дорог\n\nЗапись в хранилище — самая дорогая операция в EVM. Вот почему:\n\n### Дерево состояний Ethereum\n\nEthereum хранит всё состояние в **модифицированном Merkle Patricia Trie**. Каждая запись в хранилище:\n\n1. Обновляет значение в дереве хранилища контракта.\n2. Пересчитывает хеши от листа до корня (O(log n) хеш-операций).\n3. Обновляет корень хранилища контракта в дереве состояний аккаунтов.\n4. Пересчитывает хеши дерева аккаунтов до корня.\n\nДля записи нового значения (0->ненулевое) нужно создать новый узел-лист — 20000 газа. Для обновления существующего (ненулевое->ненулевое) — 2900 газа (тёплый), потому что лист уже существует.\n\n### Практический пример: маппинг vs массив\n\n```solidity\n\u002F\u002F Сценарий: хранение 100 адресов\n\n\u002F\u002F Вариант A: mapping (каждый адрес = отдельный слот)\nmapping(uint256 => address) public addresses;\n\u002F\u002F Запись 100 адресов: 100 * 22100 = 2 210 000 газа (все холодные, 0->ненулевое)\n\n\u002F\u002F Вариант B: массив (упакованные данные)\naddress[] public addresses;\n\u002F\u002F Запись 100 адресов: массив уже инициализирован, ~100 * 5000 = 500 000 газа\n\u002F\u002F Но первоначальная инициализация длины массива: 22100 газа\n```\n\n## Паттерны оптимизации газа\n\n### 1. Кэширование слотов хранилища\n\nСамая частая и эффективная оптимизация — кэширование значений хранилища в локальных переменных:\n\n```solidity\n\u002F\u002F ПЛОХО: множественные чтения хранилища\nfunction bad(uint256 amount) external {\n    require(balances[msg.sender] >= amount);     \u002F\u002F SLOAD #1\n    balances[msg.sender] -= amount;               \u002F\u002F SLOAD #2 + SSTORE\n    totalSupply -= amount;                        \u002F\u002F SLOAD #3 + SSTORE\n    emit Transfer(msg.sender, address(0), amount);\n    require(balances[msg.sender] == 0 || balances[msg.sender] > minBalance); \u002F\u002F SLOAD #4\n}\n\n\u002F\u002F ХОРОШО: кэширование в памяти\nfunction good(uint256 amount) external {\n    uint256 senderBalance = balances[msg.sender]; \u002F\u002F SLOAD #1 (единственный)\n    require(senderBalance >= amount);\n    uint256 newBalance = senderBalance - amount;\n    balances[msg.sender] = newBalance;            \u002F\u002F SSTORE\n    totalSupply -= amount;                        \u002F\u002F SLOAD #2 + SSTORE\n    emit Transfer(msg.sender, address(0), amount);\n    require(newBalance == 0 || newBalance > minBalance); \u002F\u002F Бесплатно — из стека\n}\n\u002F\u002F Экономия: ~2200 газа (2 холодных SLOAD)\n```\n\n### 2. Упаковка переменных\n\nSolidity упаковывает переменные меньше 32 байт в один слот:\n\n```solidity\n\u002F\u002F ПЛОХО: 3 слота (3 * 2100 = 6300 газа для чтения)\ncontract Bad {\n    uint8 a;      \u002F\u002F слот 0\n    uint256 b;    \u002F\u002F слот 1 (не упаковывается с uint8 из-за размера)\n    uint8 c;      \u002F\u002F слот 2\n}\n\n\u002F\u002F ХОРОШО: 2 слота (2 * 2100 = 4200 газа для чтения)\ncontract Good {\n    uint8 a;      \u002F\u002F слот 0\n    uint8 c;      \u002F\u002F слот 0 (упакован с a)\n    uint256 b;    \u002F\u002F слот 1\n}\n\u002F\u002F Экономия: 2100 газа за каждое чтение\n```\n\n### 3. Использование calldata вместо memory\n\n```solidity\n\u002F\u002F ПЛОХО: копирует весь массив в память\nfunction sumBad(uint256[] memory arr) external pure returns (uint256 total) {\n    for (uint256 i; i \u003C arr.length; i++) {\n        total += arr[i];\n    }\n}\n\n\u002F\u002F ХОРОШО: читает напрямую из calldata\nfunction sumGood(uint256[] calldata arr) external pure returns (uint256 total) {\n    for (uint256 i; i \u003C arr.length; i++) {\n        total += arr[i];\n    }\n}\n\u002F\u002F Экономия: ~60 газа за элемент + стоимость расширения памяти\n```\n\n### 4. Использование unchecked для безопасной арифметики\n\nНачиная с Solidity 0.8, арифметические операции проверяют переполнение по умолчанию. Каждая проверка стоит ~100 газа:\n\n```solidity\n\u002F\u002F С проверками (по умолчанию в Solidity 0.8+)\nfunction withChecks(uint256 a, uint256 b) external pure returns (uint256) {\n    return a + b; \u002F\u002F ~130 газа (ADD + проверка переполнения)\n}\n\n\u002F\u002F Без проверок (когда переполнение невозможно)\nfunction withoutChecks(uint256 a, uint256 b) external pure returns (uint256) {\n    unchecked {\n        return a + b; \u002F\u002F ~30 газа (только ADD)\n    }\n}\n\n\u002F\u002F Типичное применение: счётчик цикла\nfor (uint256 i; i \u003C length;) {\n    \u002F\u002F ... тело цикла ...\n    unchecked { ++i; } \u002F\u002F Экономия ~100 газа за итерацию\n}\n```\n\n### 5. Короткое замыкание условий\n\nSolidity использует ленивое вычисление для `&&` и `||`. Порядок условий имеет значение:\n\n```solidity\n\u002F\u002F ПЛОХО: дорогое условие проверяется первым\nrequire(expensiveCheck() && cheapCheck());\n\n\u002F\u002F ХОРОШО: дешёвое условие проверяется первым\nrequire(cheapCheck() && expensiveCheck());\n\u002F\u002F Если cheapCheck() ложно, expensiveCheck() не выполняется\n```\n\n## Лимит газа блока и его влияние\n\nЛимит газа блока в Ethereum — 30 миллионов газа (целевой — 15 миллионов). Это означает:\n\n- Максимум ~1500 простых переводов ETH в одном блоке (30M \u002F 21000)\n- Максимум ~500-800 ERC-20 трансферов в одном блоке\n- Один сложный DeFi-своп может потреблять 200000-500000 газа\n\nДля разработчиков MEV-ботов это создаёт прямое давление: чем меньше газа потребляет ваш бот, тем больше прибыли остаётся после оплаты газа. Бот, потребляющий 100000 газа вместо 200000, имеет вдвое большую маржу.\n\n## Профилирование газа: инструменты\n\nДля точного анализа газа используйте следующие инструменты:\n\n1. **Foundry gas reports** — `forge test --gas-report` показывает потребление газа для каждой функции.\n2. **Hardhat gas reporter** — плагин, генерирующий таблицу газа для всех вызовов в тестах.\n3. **Tenderly** — визуальный дебаггер транзакций с разбивкой газа по опкодам.\n4. **EVM Playground** — интерактивная среда для экспериментов с опкодами.\n\n```bash\n# Foundry: запуск тестов с отчётом о газе\nforge test --gas-report\n\n# Результат:\n# | Contract | Function | Min | Avg  | Max  | # calls |\n# |----------|----------|-----|------|------|---------|\n# | Token    | transfer | 29k | 45k  | 51k  | 100     |\n# | Token    | approve  | 24k | 24k  | 24k  | 50      |\n```\n\n## EIP-4844: блобы и газ данных\n\nEIP-4844 (обновление Dencun, март 2024) ввёл новый тип транзакции с **блобами** — большими фрагментами данных (до 128 КБ), используемыми L2-роллапами для публикации данных. Блобы имеют отдельный рынок газа с собственной базовой ставкой, значительно снижая стоимость данных для роллапов.\n\nЭто фундаментально изменило экономику L2: стоимость публикации данных на L1 упала в 10-100 раз, что напрямую снижает стоимость транзакций для пользователей L2.\n\n## Заключение\n\nГаз — это сердце экономической модели Ethereum. Понимание его механизмов — от внутреннего газа транзакции до квадратичной стоимости памяти и дифференцированной стоимости хранилища — позволяет писать контракты, которые экономят пользователям реальные деньги. Каждая из описанных оптимизаций — кэширование хранилища, упаковка переменных, использование calldata — это не микрооптимизация, а архитектурное решение.\n\nВ следующей статье мы перейдём к безопасности: как msg.sender, контроль доступа и защита от реентрабельности работают на уровне EVM.","\u003Ch2 id=\"evm\">Газ: экономическая модель EVM\u003C\u002Fh2>\n\u003Cp>Газ в Ethereum — это не просто техническое ограничение. Это экономическая система, которая ценит вычислительные ресурсы, предотвращает злоупотребления и определяет, сколько стоит ваш контракт для пользователей. Каждый опкод, каждое обращение к памяти, каждая запись в хранилище — всё измеряется в газе.\u003C\u002Fp>\n\u003Cp>Понимание газа на глубоком уровне — это разница между контрактом, который стоит $2 за транзакцию, и контрактом, который стоит $0.20. В мире DeFi и MEV это разница между прибыльным и убыточным бизнесом.\u003C\u002Fp>\n\u003Ch2 id=\"\">Анатомия стоимости транзакции\u003C\u002Fh2>\n\u003Cp>Стоимость транзакции в Ethereum складывается из нескольких компонентов:\u003C\u002Fp>\n\u003Ch3>1. Внутренний газ (Intrinsic Gas)\u003C\u002Fh3>\n\u003Cp>Каждая транзакция начинается с базовой стоимости:\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Компонент\u003C\u002Fth>\u003Cth>Стоимость\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Базовая стоимость транзакции\u003C\u002Ftd>\u003Ctd>21000 газа\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Ненулевой байт calldata\u003C\u002Ftd>\u003Ctd>16 газа\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Нулевой байт calldata\u003C\u002Ftd>\u003Ctd>4 газа\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Создание контракта (CREATE)\u003C\u002Ftd>\u003Ctd>32000 газа\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Список доступа: адрес\u003C\u002Ftd>\u003Ctd>2400 газа\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Список доступа: слот хранилища\u003C\u002Ftd>\u003Ctd>1900 газа\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Для простого перевода ETH (нет calldata) это ровно 21000 газа. Для вызова \u003Ccode>transfer(address,uint256)\u003C\u002Fcode> на ERC-20 — 21000 + стоимость calldata + стоимость выполнения.\u003C\u002Fp>\n\u003Cp>Calldata для \u003Ccode>transfer\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F 4 байта селектора + 32 байта адреса + 32 байта суммы = 68 байт\n\u002F\u002F Типичная стоимость: ~16 * 40 (ненулевых) + 4 * 28 (нулевых) = 752 газа\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>2. Стоимость выполнения\u003C\u002Fh3>\n\u003Cp>Это сумма газа всех выполненных опкодов. Для типичного ERC-20 transfer:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Примерная разбивка стоимости ERC-20 transfer:\n\u002F\u002F Диспетчеризация функций:     ~100 газа\n\u002F\u002F Загрузка баланса отправителя: ~2100 газа (холодный SLOAD)\n\u002F\u002F Проверка достаточности:       ~10 газа\n\u002F\u002F Обновление баланса отправителя: ~2900 газа (тёплый SSTORE, ненулевое-&gt;ненулевое)\n\u002F\u002F Загрузка баланса получателя:  ~2100 газа (холодный SLOAD)\n\u002F\u002F Обновление баланса получателя: ~20000 или 2900 газа (зависит от нулевого\u002Fненулевого)\n\u002F\u002F Эмиссия события Transfer:     ~1500 газа (LOG3 + данные)\n\u002F\u002F Возврат значения:              ~50 газа\n\u002F\u002F Итого: ~29000-51000 газа\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Обратите внимание на огромную разницу: если получатель уже имел баланс (ненулевое-&gt;ненулевое SSTORE: 2900), транзакция на ~17000 газа дешевле, чем если получатель новый (нулевое-&gt;ненулевое: 20000).\u003C\u002Fp>\n\u003Ch3>3. EIP-1559: базовая ставка и приоритет\u003C\u002Fh3>\n\u003Cp>С обновления London (август 2021) стоимость газа определяется двумя компонентами:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>общая стоимость = газ_использовано * (базовая_ставка + приоритетная_ставка)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul>\n\u003Cli>\u003Cstrong>Базовая ставка (base fee)\u003C\u002Fstrong> — алгоритмически определяется протоколом. Увеличивается, когда блоки заполнены более чем наполовину; уменьшается, когда менее. Сжигается полностью.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Приоритетная ставка (priority fee \u002F tip)\u003C\u002Fstrong> — платёж валидатору за включение транзакции. В периоды низкой нагрузки ~1-2 gwei; при высокой ~20-100+ gwei.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"sstore\">Почему SSTORE так дорог\u003C\u002Fh2>\n\u003Cp>Запись в хранилище — самая дорогая операция в EVM. Вот почему:\u003C\u002Fp>\n\u003Ch3>Дерево состояний Ethereum\u003C\u002Fh3>\n\u003Cp>Ethereum хранит всё состояние в \u003Cstrong>модифицированном Merkle Patricia Trie\u003C\u002Fstrong>. Каждая запись в хранилище:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Обновляет значение в дереве хранилища контракта.\u003C\u002Fli>\n\u003Cli>Пересчитывает хеши от листа до корня (O(log n) хеш-операций).\u003C\u002Fli>\n\u003Cli>Обновляет корень хранилища контракта в дереве состояний аккаунтов.\u003C\u002Fli>\n\u003Cli>Пересчитывает хеши дерева аккаунтов до корня.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Для записи нового значения (0-&gt;ненулевое) нужно создать новый узел-лист — 20000 газа. Для обновления существующего (ненулевое-&gt;ненулевое) — 2900 газа (тёплый), потому что лист уже существует.\u003C\u002Fp>\n\u003Ch3>Практический пример: маппинг vs массив\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F Сценарий: хранение 100 адресов\n\n\u002F\u002F Вариант A: mapping (каждый адрес = отдельный слот)\nmapping(uint256 =&gt; address) public addresses;\n\u002F\u002F Запись 100 адресов: 100 * 22100 = 2 210 000 газа (все холодные, 0-&gt;ненулевое)\n\n\u002F\u002F Вариант B: массив (упакованные данные)\naddress[] public addresses;\n\u002F\u002F Запись 100 адресов: массив уже инициализирован, ~100 * 5000 = 500 000 газа\n\u002F\u002F Но первоначальная инициализация длины массива: 22100 газа\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">Паттерны оптимизации газа\u003C\u002Fh2>\n\u003Ch3>1. Кэширование слотов хранилища\u003C\u002Fh3>\n\u003Cp>Самая частая и эффективная оптимизация — кэширование значений хранилища в локальных переменных:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F ПЛОХО: множественные чтения хранилища\nfunction bad(uint256 amount) external {\n    require(balances[msg.sender] &gt;= amount);     \u002F\u002F SLOAD #1\n    balances[msg.sender] -= amount;               \u002F\u002F SLOAD #2 + SSTORE\n    totalSupply -= amount;                        \u002F\u002F SLOAD #3 + SSTORE\n    emit Transfer(msg.sender, address(0), amount);\n    require(balances[msg.sender] == 0 || balances[msg.sender] &gt; minBalance); \u002F\u002F SLOAD #4\n}\n\n\u002F\u002F ХОРОШО: кэширование в памяти\nfunction good(uint256 amount) external {\n    uint256 senderBalance = balances[msg.sender]; \u002F\u002F SLOAD #1 (единственный)\n    require(senderBalance &gt;= amount);\n    uint256 newBalance = senderBalance - amount;\n    balances[msg.sender] = newBalance;            \u002F\u002F SSTORE\n    totalSupply -= amount;                        \u002F\u002F SLOAD #2 + SSTORE\n    emit Transfer(msg.sender, address(0), amount);\n    require(newBalance == 0 || newBalance &gt; minBalance); \u002F\u002F Бесплатно — из стека\n}\n\u002F\u002F Экономия: ~2200 газа (2 холодных SLOAD)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>2. Упаковка переменных\u003C\u002Fh3>\n\u003Cp>Solidity упаковывает переменные меньше 32 байт в один слот:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F ПЛОХО: 3 слота (3 * 2100 = 6300 газа для чтения)\ncontract Bad {\n    uint8 a;      \u002F\u002F слот 0\n    uint256 b;    \u002F\u002F слот 1 (не упаковывается с uint8 из-за размера)\n    uint8 c;      \u002F\u002F слот 2\n}\n\n\u002F\u002F ХОРОШО: 2 слота (2 * 2100 = 4200 газа для чтения)\ncontract Good {\n    uint8 a;      \u002F\u002F слот 0\n    uint8 c;      \u002F\u002F слот 0 (упакован с a)\n    uint256 b;    \u002F\u002F слот 1\n}\n\u002F\u002F Экономия: 2100 газа за каждое чтение\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>3. Использование calldata вместо memory\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F ПЛОХО: копирует весь массив в память\nfunction sumBad(uint256[] memory arr) external pure returns (uint256 total) {\n    for (uint256 i; i &lt; arr.length; i++) {\n        total += arr[i];\n    }\n}\n\n\u002F\u002F ХОРОШО: читает напрямую из calldata\nfunction sumGood(uint256[] calldata arr) external pure returns (uint256 total) {\n    for (uint256 i; i &lt; arr.length; i++) {\n        total += arr[i];\n    }\n}\n\u002F\u002F Экономия: ~60 газа за элемент + стоимость расширения памяти\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>4. Использование unchecked для безопасной арифметики\u003C\u002Fh3>\n\u003Cp>Начиная с Solidity 0.8, арифметические операции проверяют переполнение по умолчанию. Каждая проверка стоит ~100 газа:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F С проверками (по умолчанию в Solidity 0.8+)\nfunction withChecks(uint256 a, uint256 b) external pure returns (uint256) {\n    return a + b; \u002F\u002F ~130 газа (ADD + проверка переполнения)\n}\n\n\u002F\u002F Без проверок (когда переполнение невозможно)\nfunction withoutChecks(uint256 a, uint256 b) external pure returns (uint256) {\n    unchecked {\n        return a + b; \u002F\u002F ~30 газа (только ADD)\n    }\n}\n\n\u002F\u002F Типичное применение: счётчик цикла\nfor (uint256 i; i &lt; length;) {\n    \u002F\u002F ... тело цикла ...\n    unchecked { ++i; } \u002F\u002F Экономия ~100 газа за итерацию\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>5. Короткое замыкание условий\u003C\u002Fh3>\n\u003Cp>Solidity использует ленивое вычисление для \u003Ccode>&amp;&amp;\u003C\u002Fcode> и \u003Ccode>||\u003C\u002Fcode>. Порядок условий имеет значение:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F ПЛОХО: дорогое условие проверяется первым\nrequire(expensiveCheck() &amp;&amp; cheapCheck());\n\n\u002F\u002F ХОРОШО: дешёвое условие проверяется первым\nrequire(cheapCheck() &amp;&amp; expensiveCheck());\n\u002F\u002F Если cheapCheck() ложно, expensiveCheck() не выполняется\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">Лимит газа блока и его влияние\u003C\u002Fh2>\n\u003Cp>Лимит газа блока в Ethereum — 30 миллионов газа (целевой — 15 миллионов). Это означает:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Максимум ~1500 простых переводов ETH в одном блоке (30M \u002F 21000)\u003C\u002Fli>\n\u003Cli>Максимум ~500-800 ERC-20 трансферов в одном блоке\u003C\u002Fli>\n\u003Cli>Один сложный DeFi-своп может потреблять 200000-500000 газа\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Для разработчиков MEV-ботов это создаёт прямое давление: чем меньше газа потребляет ваш бот, тем больше прибыли остаётся после оплаты газа. Бот, потребляющий 100000 газа вместо 200000, имеет вдвое большую маржу.\u003C\u002Fp>\n\u003Ch2 id=\"\">Профилирование газа: инструменты\u003C\u002Fh2>\n\u003Cp>Для точного анализа газа используйте следующие инструменты:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Foundry gas reports\u003C\u002Fstrong> — \u003Ccode>forge test --gas-report\u003C\u002Fcode> показывает потребление газа для каждой функции.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Hardhat gas reporter\u003C\u002Fstrong> — плагин, генерирующий таблицу газа для всех вызовов в тестах.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tenderly\u003C\u002Fstrong> — визуальный дебаггер транзакций с разбивкой газа по опкодам.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>EVM Playground\u003C\u002Fstrong> — интерактивная среда для экспериментов с опкодами.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Foundry: запуск тестов с отчётом о газе\nforge test --gas-report\n\n# Результат:\n# | Contract | Function | Min | Avg  | Max  | # calls |\n# |----------|----------|-----|------|------|---------|\n# | Token    | transfer | 29k | 45k  | 51k  | 100     |\n# | Token    | approve  | 24k | 24k  | 24k  | 50      |\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"eip-4844\">EIP-4844: блобы и газ данных\u003C\u002Fh2>\n\u003Cp>EIP-4844 (обновление Dencun, март 2024) ввёл новый тип транзакции с \u003Cstrong>блобами\u003C\u002Fstrong> — большими фрагментами данных (до 128 КБ), используемыми L2-роллапами для публикации данных. Блобы имеют отдельный рынок газа с собственной базовой ставкой, значительно снижая стоимость данных для роллапов.\u003C\u002Fp>\n\u003Cp>Это фундаментально изменило экономику L2: стоимость публикации данных на L1 упала в 10-100 раз, что напрямую снижает стоимость транзакций для пользователей L2.\u003C\u002Fp>\n\u003Ch2 id=\"\">Заключение\u003C\u002Fh2>\n\u003Cp>Газ — это сердце экономической модели Ethereum. Понимание его механизмов — от внутреннего газа транзакции до квадратичной стоимости памяти и дифференцированной стоимости хранилища — позволяет писать контракты, которые экономят пользователям реальные деньги. Каждая из описанных оптимизаций — кэширование хранилища, упаковка переменных, использование calldata — это не микрооптимизация, а архитектурное решение.\u003C\u002Fp>\n\u003Cp>В следующей статье мы перейдём к безопасности: как msg.sender, контроль доступа и защита от реентрабельности работают на уровне EVM.\u003C\u002Fp>\n","ru","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:23.395060Z","Детальный анализ модели газа Ethereum: расчёт стоимости транзакций, стоимость SSTORE и паттерны оптимизации газа.","EVM газ оптимизация",null,"index, follow",[21,26,30],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000014","Solidity","solidity","Блокчейн",[36,42,48],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":34,"published_at":41},"de000000-0000-0000-0000-000000000013","Уровень интероперабельности Ethereum: как 55+ L2 становятся одной сетью","uroven-interoperabelnosti-ethereum-kak-55-l2-stanovyatsya-odnoj-setyu","У Ethereum 55+ роллапов Layer 2, фрагментирующих ликвидность и пользовательский опыт. Уровень интероперабельности Ethereum — объединяющий кросс-роллап-мессаджинг, общие секвенсоры и based-роллапы — призван объединить их в единую компонуемую сеть.","2026-03-28T10:44:36.068675Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":34,"published_at":47},"de000000-0000-0000-0000-000000000012","ZK-доказательства за пределами роллапов: верифицируемый AI-инференс на Ethereum","zk-dokazatelstva-za-predelami-rollapov-verificiruemyj-ai-inferens-ethereum","Доказательства с нулевым разглашением — это уже не только инструмент масштабирования. В 2026 году zkML обеспечивает верифицируемый AI-инференс в блокчейне, ZK-копроцессоры переносят тяжёлые вычисления оффчейн с ончейн-верификацией, а новые системы доказательств SP1 и Jolt делают это практичным.","2026-03-28T10:44:36.026310Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":34,"published_at":53},"dd000000-0000-0000-0000-000000000013","EIP-7702 на практике: создание потоков смарт-аккаунтов после Pectra","eip-7702-na-praktike-sozdanie-potokov-smart-akkauntov-posle-pectra","EIP-7702 позволяет любому EOA Ethereum временно действовать как смарт-контракт в рамках одной транзакции. Вот как реализовать пакетные транзакции, спонсирование газа и социальное восстановление с помощью нового примитива абстракции аккаунтов.","2026-03-28T10:44:35.357227Z",{"id":13,"name":55,"slug":56,"bio":57,"photo_url":18,"linkedin":18,"role":58,"created_at":59,"updated_at":59},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]