﻿---
title: "Коллизия хранилища прокси: как обновление повреждает состояние контракта"
description: "Прокси сохраняет состояние, пока код реализации меняется. Узнайте, как несовместимые схемы перезаписывают балансы, владельцев и управление обновлением и как безопасно проверить обновление."
image: "https://wiki.fcontext.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://wiki.fcontext.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Коллизия хранилища прокси: как обновление повреждает состояние контракта

> Материал предназначен только для образовательных целей и не является инвестиционной рекомендацией. Инвестиции могут привести к убыткам.

<a id="answer"></a>

## Прямой ответ

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

При `delegatecall` байткод реализации выполняется в контексте прокси: хранилище, баланс и `address(this)` принадлежат прокси. Имена переменных не хранятся в блокчейне, поэтому EVM использует только слот и смещение в байтах, рассчитанные новым кодом.

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

<a id="mechanism"></a>

## Как это работает

Обычно Solidity размещает переменные состояния начиная со слота `0` в порядке объявления после C3-линеаризации наследования. Значения меньше 32 байт могут делить слот; для структур и массивов действуют дополнительные правила, а mapping и динамические массивы вычисляют положение данных из базового слота. Сдвиг базового слота меняет и положение производных данных.

Проверять нужно четыре разные границы коллизии:

- **Прокси и реализация:** собственные поля прокси, включая адрес реализации и администратора, не должны занимать слоты состояния приложения. ERC-1967 задает стандартные слоты вне обычного распределения компилятора для реализации, beacon и администратора.
- **Старая и новая реализации:** существующие переменные должны сохранять совместимые слоты, смещения и типы. Добавление в конец может быть безопасным, а вставка, перестановка, удаление или смена типа переосмысливает существующие слова.
- **Наследование:** добавление состояния в базовый контракт или изменение порядка наследования может сдвинуть хранилище потомков, даже если их исходный код не менялся.
- **Зарезервированное или изолированное хранилище:** корректное использование storage gap резервирует место для базового контракта, а пространства имен в стиле ERC-7201 изолируют схемы. Ни один способ не разрешает произвольные изменения внутри существующей схемы.

<a id="example"></a>

## Пример

Пусть версия 1 имеет такую схему:

```solidity
uint256 totalAssets; // slot 0
address owner;       // slot 1
```

Версия 2 ошибочно вставляет переменную в начало:

```solidity
bool paused;         // slot 0, offset 0
uint256 totalAssets; // slot 1
address owner;       // slot 2
```

После обновления `paused` читает младший байт старого `totalAssets`, новый `totalAssets` трактует слово старого `owner` как целое число, а `owner` читает прежнее содержимое слота `2`, часто ноль. Исходные слова остаются в хранилище, но новый код придает им другой смысл. Транзакция может завершиться успешно, применив авторизацию или учет к искаженному состоянию.

<a id="risks"></a>

## Риски и проверки обновления

- Получите схему хранилища обеих реализаций и сравните слот, смещение, тип и наследование с фактически развернутым эталонным контрактом.
- В обычной линейной схеме добавляйте переменные только в конец. Без доказательства совместимости не меняйте порядок или тип полей, не удаляйте и не используйте их повторно, не изменяйте базовые контракты.
- При использовании storage gap уменьшайте его ровно на число занятых резервных слотов. Для пространств имен сохраняйте уникальные идентификаторы и проверяйте изменения в каждом существующем пространстве.
- Не считайте ERC-1967 полной защитой. Он отделяет метаданные прокси от слотов приложения, выделяемых компилятором, но не делает две схемы реализации совместимыми.
- Тестируйте обновление и повторную инициализацию на форке или снимке состояния. До и после выполнения проверяйте владельцев, роли, балансы, разрешения, элементы mapping, паузу, слоты реализации и средства отката или аварийного управления.

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

<a id="misconceptions"></a>

## Распространенные заблуждения

- **«Имена переменных не изменились, значит схема безопасна».** Положение определяют не имена, а типы, порядок, упаковка, наследование и правила пространств имен.
- **«Удаление переменной освобождает слот».** Хранилище прокси сохраняется. Повторное использование придает старому слову новый смысл, если проверенная миграция не очистит или не преобразует его.
- **«Успешная тестовая транзакция доказывает совместимость».** Она может затронуть лишь несколько слотов. Проверка схемы и различий состояния должна охватывать привилегированные поля, упакованные значения, mapping, массивы и унаследованное хранилище.

<a id="related"></a>

## Связанные темы

- [Риск хранилища при delegatecall](/ru/crypto/delegatecall-storage-risk/)
- [Захват инициализатора](/ru/crypto/initializer-takeover/)
- [Прокси-контракт](/ru/crypto/proxy-contract/)
- [Мониторинг обновлений прокси](/ru/crypto/proxy-upgrade-monitoring/)
- [Обновляемый контракт](/ru/crypto/upgradeable-contract/)

<a id="sources"></a>

## Источники

- [Введение в смарт-контракты](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html) - Solidity Documentation (дата обращения: 2026-08-21)
- [Размещение переменных состояния в хранилище](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html) - Solidity Documentation (дата обращения: 2026-08-21)
- [ERC-1967: слоты хранилища прокси](https://eips.ethereum.org/EIPS/eip-1967) - Ethereum Improvement Proposals (дата обращения: 2026-08-21)
- [Разработка обновляемых контрактов](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable) - OpenZeppelin Documentation (дата обращения: 2026-08-21)

Source: https://wiki.fcontext.com/ru/crypto/proxy-storage-collision/index.mdx
