
0. Обзор
- Безопасность экосистемы Solana (1) — Привет, Solana
- Безопасность экосистемы Solana (2) — Вызовы между программами
1. Обзор
В предыдущем блоге мы рассказали о том, как реализовать межпрограммный вызов с помощью функций invoke и invoke_signed. В этой статье мы рассмотрим еще одну базовую тему — обновление программ (Program Upgrade).
2. Развертывание обновляемой программы
По умолчанию все программы в Solana развертываются с использованием загрузчика BPFLoaderUpgradeable, что означает возможность их обновления. Помимо этого, Solana предоставляет опцию --final, гарантирующую, что развернутая программа будет неизменяемой. В этом случае для развертывания программы будет использован загрузчик BPFLoader2. После такого развертывания программу обновить будет невозможно.
Загрузчик BPFLoaderUpgradeable управляет тремя типами аккаунтов: аккаунтами программ, аккаунтами данных программ и аккаунтами буферов. В процессе развертывания сначала создается аккаунт буфера. Затем инструменты командной строки Solana (CLI) загружают байт-код целевой программы и записывают его в аккаунт буфера. В конечном итоге байт-код, хранящийся в аккаунте буфера, копируется в аккаунт данных программы.
Таким образом, аккаунты буферов используются загрузчиком Upgradeable BPF для временного хранения байт-кода во время процесса развертывания, аккаунты данных программ хранят реальные данные программы, а аккаунты программ работают как прокси, указывающие на соответствующие аккаунты данных программ.
Ниже мы рассмотрим несколько примеров того, как обновить вашу программу. Весь код, используемый в этой статье, можно найти здесь.
2.1 Обзор кода (Rectangle_Area)

В этом примере контракта мы определяем структуру под названием Rectangle, которая содержит три атрибута: width (ширина), height (высота) и area (площадь), с 13-й по 17-ю строку. Мы также определяем функцию area() для Rectangle. Функция area() предназначена для расчета площади прямоугольника с использованием width и height.

В функции process_instruction() мы сначала используем функцию unpack_u32() для извлечения width и height прямоугольника из данных инструкции (строки 45–46). В строке 51 извлекается аккаунт, используемый для хранения данных прямоугольника. В строке 59 функция try_from_slice_unchecked() десериализует данные аккаунта в тип структуры Rectangle. Далее мы присваиваем данные соответствующим полям структуры и вычисляем значение площади (строки 61–63). Последний шаг — сериализовать данные и записать их обратно в аккаунт данных.
Развернутую программу можно найти по следующей ссылке:
https://explorer.solana.com/address/84mMqHRTQT6b2vfsD7XRxVKA3XMd7xoEXFdF6pLNw8y?cluster=testnet
2.2 Отправка транзакции

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

Затем мы отправляем другую транзакцию для расчета площади прямоугольника и сохранения её в аккаунт данных.
Транзакцию можно найти по следующей ссылке:
https://explorer.solana.com/tx/4PybjXGRpuPKpak7FAz4BKMbcQCWmway69zAxtTnpFRuTTg7onyxW7agSe6ETx44iAGexbgnBUa8WdzdTTQSawJ3?cluster=testnet
3. Обновление
Теперь мы хотим добавить в программу новую функцию — расчет периметра прямоугольника.

После компиляции обновленного проекта мы обновляем развернутую программу в сети с помощью следующей команды:
solana program deploy /path/to/program.so --program-id <PROGRAM_ID>
Контракт может быть обновлен напрямую, и вы можете просмотреть соответствующую транзакцию ниже:
https://explorer.solana.com/tx/4Dm9v4zMiijKjQBhatx1D9xbV9PvMLdaonUWLaC2VwzkFvzdgorzbX5vsy4VQ7VxSUmqadftjiDzbyUmXgQchYmk?cluster=testnet
Затем мы отправляем транзакцию в программу, чтобы убедиться, что она успешно обновлена. Результат показывает, что функция работает корректно.
Соответствующую транзакцию можно найти ниже:
https://explorer.solana.com/tx/21c2G7kPVktAtdUFkH3QwGVi7orajRmy5PJo1UxX1mmAMU68eUkNuLzWYJRBaTzwGi5DxeocYjHfpWiU4hcSFtpQ?cluster=testnet
4. Повторное обновление

В этот раз мы хотим сохранять вычисленный периметр в аккаунт данных. Для этого мы добавляем еще один атрибут perimeter в структуру Rectangle (строка 18).

Поскольку структура аккаунта данных отличается от предыдущей, нам нужно сначала прочитать данные из него. Мы десериализуем сохраненные данные, используя исходную структуру (т.е. OldRectangle). После этого мы присваиваем соответствующие атрибуты новой структуре (т.е. CurrentRectangle) и инициализируем новый атрибут (perimeter).

Наконец, мы вычисляем значение периметра и присваиваем его обратно в update_account перед сериализацией в account_data.
Транзакцию для обновления можно найти ниже:
https://explorer.solana.com/tx/5J3oKxZXtCi755gD7pMnVh48AFvmeVzRLPgJiyNn8JFeCKx1xpAfJtsi34zjyYKJmnMk8LtC3bcwfFSP7H2gtj5o?cluster=testnet
После обновления мы можем проверить данные, хранящиеся в аккаунте, с помощью команды solana account <DataAccount>. Вы увидите, что атрибуты сохранены в первых 32 байтах. Весь процесс обновления завершен.

5. Заключение
В этой статье мы рассказали о том, как программа может быть обновлена в Solana. Мы использовали разные примеры, чтобы проиллюстрировать детальный процесс. Следите за обновлениями, скоро появятся новые статьи по Solana.
Читайте другие статьи из этой серии:
- Безопасность экосистемы Solana (1) — Привет, Solana
- Безопасность экосистемы Solana (2) — Вызовы между программами
- Безопасность экосистемы Solana (4) — Проверка аккаунтов
- Безопасность экосистемы Solana (5) — Мультиподпись
- Безопасность экосистемы Solana (6) — Мультиподпись 2
- Безопасность экосистемы Solana (7) — Спутывание типов
О BlockSec
BlockSec — это передовая компания в сфере блокчейн-безопасности, основанная в 2021 году группой всемирно признанных экспертов по безопасности. Компания стремится повысить безопасность и удобство использования для развивающегося мира Web3, чтобы способствовать его массовому внедрению. Для этого BlockSec предоставляет услуги аудита безопасности смарт-контрактов и EVM-сетей, платформу Phalcon для разработки безопасности и проактивного блокирования угроз, платформу MetaSleuth для отслеживания средств и расследований, а также расширение MetaSuites для эффективной работы разработчиков Web3 в криптомире.
На сегодняшний день компания обслужила более 300 уважаемых клиентов, таких как MetaMask, Uniswap Foundation, Compound, Forta и PancakeSwap, и получила десятки миллионов долларов США в двух раундах финансирования от выдающихся инвесторов, включая Matrix Partners, Vitalbridge Capital и Fenbushi Capital.
Официальный сайт: https://blocksec.com/
Официальный аккаунт в Twitter: https://twitter.com/BlockSecTeam



