Back to Blog

Безопасность экосистемы Solana (6) — Multi-Sig2

24 апреля 2022 г.
5 min read

0. Обзор

1. Обзор

В предыдущей статье мы обсуждали реализацию мультиподписи. Однако эта реализация предполагает, что подписи от нескольких пользователей могут быть собраны одновременно вне сети (off-chain). В этом посте мы представляем более общую программу мультиподписи, которая позволяет пользователям подписывать транзакции полностью в сети (on-chain).

2. Разработка тестовой программы

Программа мультиподписи позволяет валидным подписантам подписывать предложение по отдельности, и любой пользователь может выполнить его, как только оно будет одобрено (собрано достаточное количество подписей). Весь тестовый код можно найти здесь.

3. Обзор кода

Эта программа вводит две дополнительные структуры: TransactionAccount и Transaction. Структура TransactionAccount предназначена для записи информации об аккаунте, используемом для предлагаемой транзакции. Структура Transaction используется для записи данных предложения. Обратите внимание, что атрибут signers используется для учета количества валидных подписей. Поля did_execute и is_initialized гарантируют, что выполнение и инициализация могут быть произведены только один раз.

Программа предоставляет пять различных инструкций. Инструкция AllocatePDA предназначена для создания уникального PDA-аккаунта и использования его в качестве аккаунта самой мультиподписи (multisig). В нем будет записана информация обо всех валидных подписантах. В инструкции InitializeMultisig мы устанавливаем количество подписей, необходимых для выполнения транзакции, а также массив публичных ключей валидных подписантов. Инструкция CreateTransaction используется для создания предложения, в то время как подписант может одобрить его с помощью инструкции approve. Как только количество одобрений достигает порога, установленного в multisig, можно вызвать инструкцию ExecuteTransaction для выполнения транзакции.

Чтобы отправить предложение, пользователи могут вызвать инструкцию createTransaction(). Она принимает три аккаунта: созданный аккаунт transaction, а следующие два аккаунта используются целевой транзакцией. Чтобы предотвратить повторную инициализацию аккаунта злоумышленниками, мы проверяем атрибут is_initialized (строки 161-163). После этого мы инициализируем структуру TransactionAccount с указанными данными и сериализуем ее в аккаунт данных (строка 188).

В функции Approve() мы сначала проверяем, принадлежат ли аккаунт Transaction и аккаунт multisig данной программе. Заметьте, что при отсутствии такой проверки злоумышленники могут использовать аккаунты, созданные другими программами. Затем мы сопоставляем публичный ключ подписанта с ключами, хранящимися в аккаунте multisig. Если есть совпадение, подпись валидируется, а соответствующее значение меняется на true.

В инструкции ExecuteTransaction() мы подсчитываем количество валидных подписей. Если количество не достигает порогового значения, программа отклоняет выполнение.

После этого мы инициализируем целевую инструкцию Instruction с заданными атрибутами и вызываем инструкцию целевой программы с помощью функции invoke_signed(). В завершение мы устанавливаем атрибут did_execute в значение true, чтобы предложение не было выполнено повторно.

Мы развернули программу в тестовой сети (testnet), ее можно найти по следующей ссылке.

https://explorer.solana.com/address/CPzn7ptnJntjUB4NGKqQGRai8NFLNwFaspmJ7nEGbMHe?cluster=testnet

4. Отправка транзакции

После развертывания мы сначала создаем аккаунт multisig и устанавливаем его в качестве администратора аккаунта config при инициализации последнего. Соответствующие транзакции показаны ниже, их порядок следующий: createMultisig() (в General-Multisig) -> развертывание программы PriviligeOwner -> Allocate() (в PrivligeOwner) -> InitializeConfig() (в PrivligeOwner).

https://explorer.solana.com/tx/2vXHmwbCsARstx8wi4eLACbrb6PuZZMktsqU8VnJLp64fvrpaE62QSTn5QLczzxnTvxRLWMSR3dKLGYXZasGMn69?cluster=testnet
https://explorer.solana.com/tx/2EMq9y6HNnXq1n2XsqrBkJd8RGL27PCj5T4JyJ71ZoA3ipUggT6dF6S6uDv4TtxGGKk8BmiAJHS7BFRgZqWjkWVb?cluster=testnet
https://explorer.solana.com/tx/3UhXKsTubUiPqRtLyNYskxvbyrTKHsbeptxuAfJQ348AU4b8gQET2HAMaqxwud6Wo3MKTYHWBneqa9z2WhCpwV6t?cluster=testnet
https://explorer.solana.com/tx/5NA7Yw23uRf48Q3BYM21dtS7gD9YMECij43ZaRLMPe7svt3bsv2TPWwbCRP5akDmttjLEHWZtpqrZrVLNr9QLyJY?cluster=testnet

Затем мы вызываем инструкцию InitializeMultisig(). Мы передаем четыре аккаунта: аккаунт multisig и три аккаунта валидных подписантов. Мы устанавливаем значение m равным 2, что означает, что для выполнения привилегированных функций требуются подписи двух из трех подписантов.

В функции CreateTransaction() мы передаем созданный аккаунт Transaction, публичный ключ целевой программы (PrivilegeOwner) и публичный ключ аккаунта config (строки 306-307). Кроме того, мы должны установить _data в значение 3, что соответствует инструкции unlock() в программе PrivilegeOwner.

Для первого теста созданное предложение одобряет только один подписант. В этом случае ExecuteTransaction() завершается с ошибкой, так как собрано недостаточно подписей. Консоль выводит следующее сообщение.

Другой подписант одобряет созданное предложение и вызывает ExecuteTransaction(). Общее количество подписей достигло порога, поэтому предложение выполняется успешно.

https://explorer.solana.com/tx/55Qy93RxybsT7c5v9AFgN8Dt1h3AVJfbsosLbstYVB6paY1wmau5sdtLfGpfryXnZTsBNRauvwLSmAu2nABFxVCe?cluster=testnet
https://explorer.solana.com/tx/4XF4MUhL4oftkDt4sn7NoREmGqcDMVP6HGypvJQMtiAbBKiCuy4B98vhQKtvm4mPv7SprrDDVsiwgb6pNwgJcTwz?cluster=testnet

4. Резюме

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

Читайте другие статьи этой серии:

О компании 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

Sign up for the latest updates
Как решение BlockSec по обеспечению безопасности платежей помогает организациям оставаться защищёнными в эпоху ИИ
Security Services

Как решение BlockSec по обеспечению безопасности платежей помогает организациям оставаться защищёнными в эпоху ИИ

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

Потери около 5,57 млн USD: атаки на X100 Freezer и NEM | Еженедельный обзор BlockSec
Security Insights

Потери около 5,57 млн USD: атаки на X100 Freezer и NEM | Еженедельный обзор BlockSec

Этот еженедельный отчёт охватывает два инцидента безопасности в сетях Ethereum и BNB Chain за период 19.10.2026–25.10.2026. В нём рассматриваются захват управления X100 Freezer, профинансированный с помощью флеш-кредита, и ошибка при расчёте налога, затронувшая пул ликвидности токена NEM в сети BNB Chain. Оценочные потери в рамках отчёта составляют в общей сложности около 5,57 млн USD: ~4,75 млн USD по рассматриваемой транзакции X100 и ~820 тыс. USD в результате инцидента с пулом NEM. В эту сумму не входят отдельно опубликованные данные о последующих выводах средств из X100.

Потери на сумму около 3,87 млн USD: взломы Autheo Network и UNCX | Еженедельный обзор BlockSec
Security Insights

Потери на сумму около 3,87 млн USD: взломы Autheo Network и UNCX | Еженедельный обзор BlockSec

В этом еженедельном отчёте рассматриваются 3 инцидента безопасности за период 12.10.2026–18.10.2026. Общий оценочный ущерб составил около 3,87 млн USD. Ущерб Autheo Network от компрометации закрытого ключа составил примерно 1,76 млн USD, Qubic Wallet потерял примерно 1,30 млн USD из-за ненадёжной генерации seed, а ошибка учёта в контрактах Smart Token Vesting V2 сети UNCX Network на Ethereum, BNB Chain, Base и Robinhood Chain привела к ущербу примерно в 807 тыс. USD. В подробном анализе инцидента UNCX объясняется, как некорректный расчёт совокупного количества долей смешивал транши вестинга, созданные при разных соотношениях токенов и долей, и позволял выводить из общих пулов больше положенного.