
0. Обзор
- Безопасность экосистемы Solana (1) — Привет, Solana
- Безопасность экосистемы Solana (2) — Взаимодействие между программами
- Безопасность экосистемы Solana (3) — Обновление программы
- Безопасность экосистемы Solana (4) — Валидация аккаунтов
- Безопасность экосистемы Solana (5) — Мультиподпись (Multi-Sig)
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, когда количество валидных подписей соответствует заданным требованиям. Следите за обновлениями, и мы расскажем больше в наших будущих публикациях.
Читайте другие статьи этой серии:
- Безопасность экосистемы Solana (1) — Привет, Solana
- Безопасность экосистемы Solana (2) — Взаимодействие между программами
- Безопасность экосистемы Solana (3) — Обновление программы
- Безопасность экосистемы Solana (4) — Валидация аккаунтов
- Безопасность экосистемы Solana (5) — Мультиподпись (Multi-Sig)
- Безопасность экосистемы Solana (7) — Смешение типов (Type Confusion)
О компании 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



