Источник: Nuances of Programming
Если бы вы погуглили фразу “случайные числа в Solidity” (речь идёт об англоязычном поиске), то в самых популярных результатах выдачи было бы:
Solidity не может генерировать случайные числа. (sitepoint.com)
Не стоит генерировать случайные числа в своих смарт-контрактах, иначе вас взломают. (Medium article currently ranked #2)
Будьте осторожны. Случайные числа абсолютно прогнозируемы, а поэтому не подходят для игр на везение или любой другой ситуации, в которой участник не должен их отгадать. (Rob Hitchens on StackExchange ETH)
Все эти похожие друг на друга высказывания не слишком оптимистичны.
В прошлом генерация СЧ в блокчейне сулила катастрофу для безопасности
К счастью это изменилось. Если вы немного погружены в контекст, то я расскажу, как получилось решить эту проблему. Вместе разберемся, как сейчас можно сгенерировать подлинные случайные числа очень быстро.
А если вы чему-либо научитесь к концу этой статьи, то, умоляю, окажите мне и всему миру услугу: создайте толковый техасский холдем. Сам я не смог этого сделать пока что.
Зачем нам нужны СЧ?
Например, мы захотим провести лотерею, игру или же заполучить случайные данные для тестовых наборов данных. Раньше для этой задачи мы бы использовали актуальный хеш блока. Он бы стал основой для нашего генератора псевдослучайных чисел. Причем, это самый распространенный подход, который очень часто предлагают в туториалах.
Вариант 1: используйте текущий хеш блока
Блокчейн постоянно растет, поэтому ID-номер каждого хеша в блоке меняется. Это значит, что мы можем это использовать. В каждом блоке есть случайное число, вы в курсе, да? Опишем это в Solidity при помощи следующей функции:
function random() private view returns(uint){
return uint(keccak256(abi.encodePacked(block.difficulty, now, players)));
}
Примечание: в основе этого метода сложное устройство блоков, которое очень пригодится для рандомизации.
Вот и славно! Я считаю, что трудновато использовать хеш блока, чтобы сотворить что-то вредоносное. Подумайте над этим сами.
Неправильно
Припоминаю ту статью, в которой ругали всех, кто когда-либо создавал псевдослучайную лотерею. Система случайных чисел должна быть настолько сильной, чтобы в случае атаки (когда хакер стопроцентно знает ваш способ генерации СЧ) она все ещё оставалась непроницаемой — так сохранится непредсказуемость.
И вот есть у нас опция с хешем блока. Остается вероятность, если кто-то успеет быстро просмотреть хеш, то получится использовать это во вред вам — взломать систему, связанную со случайными числами. Без достоверных СЧ лотерею можно взломать, а вас — ограбить в любой момент.
Вы применяете описанный подход в приложении для лотереи? Если да — злоумышленники могут использовать хеш, чтобы каждый раз узнавать выигрышные числа. А это значит, что ваше лотерейное приложение может стать схемой “стань богатым быстро” для некого “Пети”.
Проблемы могут создать не только эти люди, которые быстрее всех умеют угадывать хеши блока. Мы ведь ещё должны доверять и майнеру, который хеширует ответ. Что нам остается делать, как не верить в то, что они не будут использовать свои знания во вред нашему рандомизатору?
Блокчейн был создан для того, чтобы быть максимально “честным”, насколько это возможно.
Итак, у нас возникают две главные проблемы с псевдослучайными числами.
Вариант 2: получим-ка СЧ с помощью API/Oracle
В своих статьях я уже не раз говорил, что это ужасная идея. Если ваш централизованный рандомизатор будет поврежден, подкуплен или отключен, то конец вашему смарт-контракту. Он станет бесполезным.
Возможно, той API-компании платят, чтобы они продолжали отправлять ваш смарт-контракт с неизменной цифрой 7 в сумме на двух игральных костях с 12-ю сторонами. Имеется в виду, что у вас есть цифровой вариант “читерских” игральных костей.
И это ещё не все, они могут отключаться, повреждаться или выходить из строя, а значит, когда ваша игра Catan со смарт-контрактами попытается получить дополнительные ресурсы, вы увидите типичное “404 Not Found”.
И вот сейчас я вполне уверен, что не смогу использовать ресурс 404, чтобы найти longest road(самый длинный путь). Это шутка. Странная, как и все гиковские.
Вариант 3: Chainlink VRF
Verifiable Random Function —доказуемая случайная функция.
Ну а теперь время для разговоров о хорошем.
Несколько лет назад в StackExchange опубликовали интересный вопрос: каким защищённым способом я могу сгенерировать СЧ в смарт-контракте? Актуальный тогда ответ и на сегодняшний день лучше прочей информации описывает, что именно нужно, чтобы сделать толковую систему.
Разные узлы получают запросы на СЧ. Каждый из них отправляет подлинный случайный ответ при помощи публичного и приватного ключей, а также “зачаточные” (исходные) данные.
У каждого узла есть свои побитовые XOR — это нужно для того, чтобы вместе они в итоге сгенерировали случайное число.
Если вам интересно, можете углубиться в математическую сторону этого вопроса позже, а пока вот вам две понятные основные части:
- Случайное число генерируется доказуемым случайным способом при помощи публичного и приватного ключей. Ключи нужны для криптографического доказательства, что число действительно было случайным.
- Это случайное число генерируется во многих узлах, чтобы гарантировать, что не будет уязвимого единого источника а затем будут XOR-ы (так объединяются ответы), чтобы получить финальный результат.
Такие методы часто работают в сфере блокчейна, децентрализации и криптографии (особенно в криптографии).
Процесс создания блокчейн-приложения с централизованным источником данных и оракулом похож на покупку велосипеда, чтобы больше не ходить на работу пешком, но почему-то все равно ходишь пешком только теперь уже с велосипедом, привязанным к спине.
Эти концепции — фундамент Chainlink VRF. Уже теперь в системе Chainlink есть рабочая реализация концепции #1, функционирующая в тестовой сети (с криптографически подлинными случайными числами). Также в разработке концепция #2 — расцвет метода с подлинными случайными числами, их децентрализация. Вы можете создать приложение с подлинными случайными числами на Kovan, Ropsten и Rinkeby. Хоть бы и прямо сейчас, если есть желание и\или потребность.
Сейчас Chainlink находится на финальных этапах ревью относительно безопасности для доказуемой случайной функции. Его авторы хотят пригласить наших пользователей в два сообщества: разработчики и академическая тусовка. Так что вы можете стать пользователем одного из первых приложений, работающих на смарт-контракте с проверяемыми случайными числами. Еще вы можете получить ранний доступ в момент, когда вишенка на торте в виде децентрализации будет завершена. Если захотите узнать больше подробностей из технического описания, покопайтесь в блоге компании.
Или же почитайте документацию по продукту, с нее можно начать погружение в тему.
Как получить истинные случайные числа в смарт-контрактах за 3 минуты
1. Откройте Remix
Если кликнуть по линку, для примера код в Remix сгенерируется автоматически. Тем не менее, вы можете копировать и использовать мои наработки.
Это простой контракт, который будет крутить доказуемую шестигранную кость, а потом возвращать результат в ваш контракт.
Если вы никогда не запускали смарт-контракт из Solidity, я рекомендую пройти туториал по теме или просмотреть пример из документации Chainlink.
Чтобы получить случайное число, нам нужно несколько переменных:
- keyhash: хеш публичного ключа(ей) оракула(ов) (предоставляет оракул. Это нужно для того, чтобы стопроцентно знать, что случайные числа создаются на основе зачаточных данных, которые мы туда передаем. Мы будем использовать Ropsten оракул Chainlink VRF.
- userProvidedSeed: зачаточные данные выбираем сами. Это еще один процесс, который нужен для доказательства подлинности случайных чисел. Каждый раз, когда мы вызываем rollDice, мы должны использовать разные зачаточные (исходные) данные. Если хотите разобраться в том, как это происходит, загляните сюда. Примечание: вам все еще нужно хешировать эти данные (посмотрите пример, чтобы понять контекст).
- _vrfcoordinator и _link: это адрес контракта координатора функции проверяемого случайного и токена Chainlink. Они строго запрограммированы в этом контракте для Ropsten.
2. Скомпилируйте контракт при помощи solidity v0.6.2
Если вы запутались, сходите сюда. Вложите свои 5–10 минут в то, чтобы стать экспертом в Remix и смарт-контрактах.
Убедитесь, что вы в Ropsten, если используете метамаску. Подобное точное прохождение сработает только для Ropsten. На разных сетях тестирования блокчейна — разные адреса.
3. Проведите развертывание при помощи injected Web3
Если нажмёте на небольшую морковку напротив опции развертывания, у вас откроется вот такой выпадающий список:
Для _vrfcoordinator введите значение 0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb, а для _link — 0x20fE562d797A42Dcb3399062AE9546cd06f63280. Это адреса контракта в Chainlink и координатора функции проверяемого случайного.
Нажмите transact или deploy и вам предложат метамаску. Нажмите “подтвердить” и подождите несколько секунд. Можете кликнуть ссылку на Etherscan. Пройдя по ней, вы увидите сами, когда завершается развертывание контракта.
4. Подкрепите свой контракт
Скопируйте адрес в Remix — нажмите маленькую иконку копирования, она находится внизу рядом с вашими развернутыми контрактами.
И отправьте какой-нибудь LINK в сеть тестирования блокчейна. Вы всегда можете получить еще больше Ropsten LINK из Chainlink Ropsten Faucet (вот там).
5. Бросайте кость
Введите любое число в функцию rollDice. После подтверждения транзакции нажмите кнопку diceRolled — увидите, что у вас выбросилось в результате.
Ну вот теперь вы знаете, как бросать кубик методом доказуемой случайности при помощи Chainlink VRF.
Если возможность стать одним из самых первых пользователей, работающих с доказуемыми случайными числами не прельщает вас, позвольте мне попробовать повысить ценность этого еще одним пунктом. Команда Chainlink славится тем, что раздает призы на хакатонах тем, кто придумал яркое применение их технологии. Иногда сумма доходит до $6,000, что сопоставимо со стоимостью токена LINK.
Поищите хакатоны для себя. Особенно, если вы новичок. Зарегистрируйтесь на AlphaVHack. Там есть начальные уровни для новых участников с адекватными призами и воркшопы для тех, кто осваивается в теме.
P.S. Спасибо за внимание! Учите английский, ребята. Есть вещи, которые навсегда останутся непереведенными, но очень полезными для вас 😉
Читайте также:
Читайте нас в телеграмме и vk
Перевод статьи Patrick Collins: How to Generate Truly Random Numbers in Solidity and Blockchain