
Как превратить идею в программу Solana (смарт-контракт)
Давайте спроектируем программу Solana. В экосистеме Solana есть множество статей о модели программирования Solana, а также небольших демонстрационных программ, которые отлично подходят начинающим для изучения Solana и Anchor. Однако при создании реальных программ нужно учитывать более сложные аспекты.
В этой статье мы рассмотрим реальную программу, которую хотим создать, и разберем:
- Представление данных в виде аккаунтов Solana
- Создание связей между данными
- Хранение токенов внутри программы
- Использование индексов для ускорения чтения
- Использование шардирования для ускорения записи
Цель этого примера — помочь вам понять, как представить собственные идеи в виде программ и аккаунтов Solana.
Примечание: предполагается, что вы знакомы с основами Anchor.
Пример программы Solana — создаем рынок предсказаний
Сегодня мы спроектируем рынок предсказаний, похожий на Polymarket, Hedgehog или Drift BET. На рынках предсказаний люди делают ставки на различные исходы событий. Например, какая команда выиграет Superbowl, кто получит «Оскар» за лучшую режиссуру, сделает ли правительство заявление к определенному моменту или чем завершится любое другое реальное событие с конкретным исходом. Если ставка сделана на победивший исход, пользователь получает выигрыш из пула ставок.
Архитектура рынка предсказаний
Вот основная архитектура рынка предсказаний и связи между ее элементами:
- Существует несколько событий.
- У каждого события есть несколько исходов. В итоге один из них будет определен как победивший.
- Пользователи делают несколько ставок на каждый исход. Когда пользователь делает ставку, его средства добавляются в призовой пул этого события.
Когда событие «разрешается» (то есть становится известен победивший исход):
- Пользователи, сделавшие ставку на победивший исход, смогут получить выигрыш
- Победители получат долю призового пула за вычетом комиссии платформы
- Доля каждого победителя в призовом пуле будет зависеть от его доли среди ставок на победивший исход.
1. Проектируем приложение в виде аккаунтов Solana
Если бы мы проектировали эту программу с использованием реляционной базы данных, то учитывали бы следующее:
- Схожие элементы данных хранятся в виде строк таблицы
- Первичные ключи однозначно идентифицируют каждый элемент данных
- Столбцы таблицы определяют ожидаемые атрибуты каждого элемента данных и их типы
В Solana этим концепциям примерно соответствуют:
- Схожие элементы данных хранятся с использованием одного типа аккаунта
- Адреса однозначно идентифицируют каждый элемент данных
- Структура (ключи и типы данных) определяет атрибуты каждого элемента
Ниже одни и те же данные представлены в виде традиционной таблицы базы данных и аккаунтов Solana:
2. Определяем связи между данными
Связи между элементами данных в Solana устроены совсем иначе. В традиционных базах данных используются отношения — логические связи между таблицами. В Solana отношения «один ко многим» представлены вектором адресов, каждый из которых указывает на аккаунт с соответствующим элементом.
Например, у событий есть «исходы», представленные вектором адресов исходов. В Anchor это обозначается как Vec<Pubkey>, хотя адреса PDA (такие как адрес нашего исхода) на самом деле не являются публичными ключами.
3. Храним токены
В отличие от традиционных баз данных, программы Solana могут хранить внутри аккаунта не только числовые значения баланса, но и сами средства.
В нашем примере событию нужен токен-аккаунт для призового пула. PDA события будет владеть аккаунтом призового пула. Когда пользователи делают ставки, они отправляют токены на этот аккаунт. Но что еще важнее, когда они получают выигрыш, наша программа подписывает транзакцию от имени аккаунта события, чтобы перевести токены из призового пула.
4. Снижаем затраты на чтение
Наша программа должна максимально быстро реагировать на действия пользователей. Кроме того, разработчикам важно не платить за лишние операции чтения аккаунтов. Накопительные итоги и индексы помогут сделать программу быстрее и эффективнее.
Рассчитываем накопительные итоги
Когда пользователи получают выигрыш, нам нужно точно знать общую сумму ставок на каждый исход. Рынки предсказаний рассчитывают выплату победителю по формуле призовой пул × сумма ставки ÷ общая сумма ставок на победивший исход.
Сейчас сумма каждой ставки хранится только в аккаунте этой ставки. Чтобы получить общую сумму ставок на определенный исход, пришлось бы прочитать каждый аккаунт ставки и сложить все суммы.
Вместо этого добавим к каждому исходу поле total_amount и будем увеличивать его значение при добавлении ставок. Тогда при победе пользователя мы сможем легко определить сумму выплаты, не читая все ставки на этот исход.
Используем индексы
Нам также потребуется находить все ставки определенного пользователя. Можно получить все аккаунты ставок с помощью getProgramAccounts(), а затем отфильтровать те, в которых адрес участника ставки совпадает с адресом пользователя. Хотя быстрый getprogramAccounts() от Helius выполняет эту операцию значительно быстрее, чем другие RPC-провайдеры, часто в качестве альтернативы используют индексы.
Создадим индекс для хранения ставок каждого пользователя. Когда пользователь делает новую ставку, мы создадим этот элемент, если его еще нет, и добавим ставку в список ставок пользователя:
Мы также добавим теги к каждому событию, чтобы легко находить все события с тегами «спорт», «политика», «Европа», «США», «политика» и так далее. Для этого создадим еще один индекс:
Теперь мы можем легко получить все интересующие события через аккаунт тега события.
5. Снижаем конкуренцию при записи
Помните, что у каждого события есть один токен-аккаунт, в котором хранятся ставки на это событие? Каждый раз, когда пользователь делает новую ставку, токены переводятся на этот аккаунт. Иными словами, в аккаунт записываются данные.
Solana работает быстро благодаря параллельному выполнению операций. Однако обновлять баланс одного аккаунта параллельно нельзя. Операции должны выполняться последовательно, поскольку в каждый момент времени у аккаунта может быть только один баланс.
Если объявить новое событие и на него одновременно поступит множество ставок, токен-аккаунт события будет обрабатываться множеством операций записи, а транзакции нашей программы могут замедлиться. Это называется конкуренцией при записи: несколько транзакций конкурируют за доступ к аккаунту.
Один из способов обеспечить параллельное выполнение в таких случаях — шардирование. Ресурс разделяется на несколько частей — шардов, к которым можно обращаться параллельно.
Как работает шардирование
Входящие платежи направляются в отдельные шарды win_pool на основе значения последнего байта публичного ключа участника ставки с помощью макроса shard_num(). Это обеспечивает быструю обработку входящих платежей.
Позже обработчик инструкции администратора может объединить их в одном аккаунте призового пула. Так в одном аккаунте будет достаточно ликвидности для выплат победителям.
Также нужно учитывать конкуренцию при записи, если популярное событие завершится и все победители одновременно запросят выплату. Нам потребуется максимально быстро переводить средства из призового пула.
Лучший вариант — отказаться от процесса запроса выплаты. Если после завершения события последовательно отправить средства пользователям, им вообще не придется сталкиваться с медленной обработкой запросов: выигрыш уже будет зачислен на их аккаунты.
Однако беспокоиться о толпах пользователей, которые делают ставки или запрашивают выплаты, стоит только после того, как у вас действительно появятся пользователи. Если вы планируете программу Solana и еще не запустили ее, оптимизация под большой объем несуществующего пользовательского трафика не нужна. Если подобные масштабные оптимизации не требуются для запуска, учитывайте сложность, которую они добавляют. При этом помните, что их, возможно, придется реализовать позже, когда программа станет популярнее.
Заключение
В этой статье мы подробно рассмотрели создание реального приложения на Solana. Теперь вы знаете, как определять аккаунты Solana, устанавливать связи между данными, хранить токены и оптимизировать производительность с помощью индексов и шардирования.
Если у вас остались вопросы, напишите @helius в X или присоединитесь к Discord Helius. В будущем мы продолжим развивать этот пример рынка предсказаний, поэтому подпишитесь на эти аккаунты, чтобы не пропустить обновления.
Теперь вы готовы превратить свои идеи в программы Solana и воплотить их в жизнь в экосистеме Solana. Удачи в разработке! Спасибо Ichigo за проверку статьи и r0bre за подсказку о технике шардирования аккаунтов.
Дополнительные ресурсы
Похожие статьи
Подпишитесь на Helius
Следите за новостями разработки на Solana и получайте уведомления о наших публикациях


