Back to Blog

Защита экосистемы Solana (1) — Привет, Solana

9 марта 2022 г.
5 min read

1. Введение

Solana — это высокопроизводительная блокчейн-система первого уровня (Layer 1) без разрешений (permissionless), которая поддерживает разработку программ (смарт-контрактов) на различных языках (например, Rust, C++ и C). Благодаря использованию механизма Tower BFT (византийская отказоустойчивость), сеть способна обрабатывать тысячи транзакций в секунду. Одной из ключевых инноваций Solana является Proof of History (PoH) — глобально доступный источник времени в сети без разрешений, который работает до достижения консенсуса. Мы более подробно обсудим PoH в будущем.

2. Наша миссия

BlockSec — это компания в сфере безопасности блокчейнов, чьей миссией является «обеспечение безопасности экосистемы DApp». Поэтому мы предоставляем не только услуги по аудиту контрактов, но и рекомендации о том, как писать безопасные смарт-контракты для всего сообщества. Учитывая популярность, высокую производительность и отличную архитектуру Solana, эта серия статей будет посвящена безопасности смарт-контрактов на Rust в сети Solana.

3. Привет, Solana

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

3.1 Обзор кода

В Solana смарт-контракт называется «программой». Программа Hello World предназначена для ведения счетчика, который записывает количество вызовов целевого аккаунта (принадлежащего программе) клиентом и выводит это число.

Давайте разберем контракт целиком.

Строки с 1 по 9 явно импортируют множество библиотек в область видимости с помощью ключевого слова use.

В строке 12 [derive(BorshSerialize, BorshDeserialize, Debug)] используется для сериализации и десериализации параметров, передаваемых в структуру GreetingAccount, которая определена в строках с 13 по 16. Структура содержит публичный член counter типа u32. После этого, как указано в комментарии, в строке 19 происходит экспорт точки входа программы — функции process_instruction.

Функция process_instruction принимает три параметра (а именно program_id, accounts и _instruction_data). Обратите внимание, что program_id — это публичный ключ (т.е. адрес) развернутой программы, а accounts содержит аккаунт, которому отправляется «приветствие». Параметр _instruction_data пуст и не используется.

Чтобы узнать больше о программах и аккаунтах в Solana, пожалуйста, обратитесь к документации Solana.

В строке 27 выводится приветственное сообщение. В строках с 30 по 33 происходит итерация по аккаунтам, и извлекается конкретный аккаунт, которому нужно отправить приветствие. После этого проверяется владелец аккаунта: он должен совпадать с program_id, чтобы гарантировать, что программа имеет право записывать данные в этот аккаунт. Наконец, greeting_account извлекается с помощью try_from_slice, и счетчик увеличивается на 1.

3.2 Компиляция программы

Для компиляции программы необходимо установить Solana CLI с помощью следующей команды:

sh -c "$(curl -sSfL https://release.solana.com/v1.9.9/install)"

Чтобы убедиться, что Solana CLI установлен успешно, можно проверить версию командой:

solana --version

Обратите внимание, что также требуются Rust и NodeJS.

Для компиляции программы используйте следующую команду:

cargo build-bpf --manifest-path=./src/program-rust/Cargo.toml --bpf-out-dir=dist/program

Скомпилированная программа будет создана в каталоге, указанном в --bpf-out-dir, под названием helloworld.so.

3.3 Развертывание контракта

Чтобы развернуть скомпилированную программу в Solana, сначала нужно выбрать кластер. В Solana существует четыре различных кластера: mainnet, testnet, devnet и localnet. В этой статье мы разворачиваем программу в devnet исключительно для демонстрации.

Мы используем следующую команду для выбора кластера:

solana config set --url https://api.devnet.solana.com

После этого нужно создать кошелек для развертывания. solana-keygen new --force помогает создать кошелек. Дополнительную информацию можно найти в документации Solana.

Поскольку у нового аккаунта нет баланса для оплаты комиссий за транзакции, мы получаем 1 SOL с помощью следующей команды:

solana airdrop 1 <YourPublicKey> --url https://api.devnet.solana.com

Теперь мы готовы развернуть контракт:

solana program deploy dist/program/helloworld.so

Пользователи могут просматривать программы и транзакции в обозревателе Devnet. В этой демонстрации вы можете найти развернутую программу по этой ссылке.

3.4 Отправка транзакции

Рекомендуется писать скрипты (клиенты) для отправки транзакций в Solana. К счастью, Solana предоставляет пример кода. Чтобы запустить клиент, сначала нужно установить его зависимости:

npm install 

После завершения установки запустим функцию main в файле main.ts с помощью команды:

npm run start 

В функции main клиент сначала устанавливает соединение с указанным кластером (т.е. Devnet) с помощью функции establishConnection(), проверяет плательщика комиссий с помощью establishPayer и подтверждает наличие программы и аккаунта, которому нужно отправить «приветствие», с помощью checkProgram. Обратите внимание: если требуемый аккаунт не существует, он будет создан путем отправки транзакции. В ходе нашей демонстрации аккаунт был создан (см. эту транзакцию).

Когда всё готово, вызывается функция sayHello. Транзакция состоит из одной инструкции. Эта инструкция получает keys, содержащие один аккаунт. Публичный ключ этого аккаунта (greetedPubkey) — это цель приветствия. Заметьте, этот аккаунт используется для хранения данных и не является подписантом (signer). В данном случае атрибут isSigner равен false, а isWritable — true. programId является владельцем greetedPubkey, он же — адрес развернутого контракта. Обратите внимание, data пуста и не используется в этой транзакции. В строке 208 вызывается функция sendAndConfirmTransaction, и транзакция отправляется в кластер.

Вы можете посмотреть детальную информацию о транзакции здесь.

4. Заключение

В этой статье мы кратко представили общую информацию о Solana и разобрали пример проекта (Hello World). Мы узнали, как развернуть программу в Solana и как использовать клиент для взаимодействия с программой в сети. Пожалуйста, продолжайте следить за нашим блогом: мы будем регулярно публиковать новые статьи в этой серии.

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

Sign up for the latest updates
За пределами безопасного хранения, часть 2: безопасная реализация криптографии кошелька
Security Insights

За пределами безопасного хранения, часть 2: безопасная реализация криптографии кошелька

Может ли злоумышленник восстановить закрытый ключ, не получив доступа к его защищённой копии? В части 2 статьи «За пределами безопасного хранения» рассматриваются шесть инцидентов, в которых недостаточная случайность, потеря энтропии или ошибки при работе с одноразовыми числами (nonce) для подписания делали ключи предсказуемыми либо позволяли их восстановить. На основе этих случаев сформулированы требования к реализации генерации ключей и подписания, а затем объясняется, как платёжные организации могут оценить их выполнение с помощью анализа кода и тестирования развёрнутой системы.

За пределами безопасного хранения, часть 1: проектирование безопасных процессов проведения платежей и подписания транзакций
Security Insights

За пределами безопасного хранения, часть 1: проектирование безопасных процессов проведения платежей и подписания транзакций

Как несанкционированная операция может получить действительную подпись, если злоумышленник не похитил закрытый ключ? В части 1 материала «За пределами безопасного хранения» на примере инцидентов, в том числе связанных с Bitget, Bybit и Binance, рассматриваются сбои авторизации на этапах подачи платёжных запросов, формирования транзакций, подписания, исполнения и расчётов. На этой основе выводятся принципы проектирования, направленные на предотвращение несанкционированных операций и ограничение потерь, а затем объясняется, как проверки, аудиты, тесты на проникновение и учения могут помочь проверить эти меры защиты.

Эксплуатация уязвимости NEAR Intents: ошибка при возврате средств и уроки безопасности
Security Insights

Эксплуатация уязвимости NEAR Intents: ошибка при возврате средств и уроки безопасности

При эксплуатации уязвимости NEAR Intents события возврата с завышенными суммами использовались для сохранения внутренних балансов после возврата внесённых активов. В этом анализе прослеживается прохождение квитанций и рассматриваются семь операций вывода средств в сети BNB Chain на общую сумму 3 865 021 USDT. Эти выводы отделяются от полного возврата средств, о котором сообщил проект; также рассматриваются вопросы безопасности при разработке и аудите смарт-контрактов NEAR.