Эта статья была создана в партнерстве с iOlite . Спасибо за поддержку партнеров, которые делают возможным использование SitePoint.
Солидность — это довольно новый язык, и поскольку ни один код не идеален, он содержит проблемы, связанные с кодом и тем, что вы хотите с ним сделать. Эта статья проведет вас через лучшие практики и подводные камни при использовании случайного числа в качестве входных данных для вашего умного контракта Ethereum.
Твердость Генерация случайных чисел
Солидность не способна создавать случайные числа. Фактически, каждый алгоритм для создания случайных чисел является псевдослучайным — ни один язык не способен создавать полностью случайные числа. Проблема с Solidity заключается в том, что сложные алгоритмы стоят слишком дорого, поэтому используются более простые решения. Кроме того, код Solidity должен быть детерминированным, так как он будет работать на нескольких узлах. Нам нужен алгоритм, который способен генерировать случайное число один раз и использовать его на нескольких узлах. Такие вещи, как время на часах, недоступны для генерации случайных чисел, поэтому мы должны рассмотреть другие варианты. Как разработчик, вы должны знать об этой проблеме, потому что злоумышленник может предсказать результат в некоторых конкретных случаях.
Одним из наиболее часто используемых алгоритмов является «линейный конгруэнтный генератор» (LCG). Это один из старейших алгоритмов, быстрый и простой для понимания. LCG — хороший вариант для встраиваемых систем, поскольку они имеют ограниченный объем памяти. Однако он не очень подходит для криптографически защищенных приложений. Хотя это все еще используется в интеллектуальных контрактах, поскольку быстрый алгоритм намного дешевле в плане затрат на газ.
Сам алгоритм выполняет эти шаги:
- Принять ввод
- Выполнить алгоритм на входе
- Возьмите модуль вывода (разделите на максимальное число в требуемом диапазоне)
- Выход от 0 до максимального числа в требуемом диапазоне
Давайте рассмотрим различные способы создания случайных чисел на примере умного контракта лотереи. Пользователи могут присоединиться к лотерее, отправив 0.1 Ether в контракт вместе с целым числом от 0 до 250.
1. Block.timestamp & Block.difficulty
block.timestamp
назначается block.timestamp
всякий раз, когда он подтверждает транзакцию. Ни один из игроков нашего Лотерейного контракта не может его контролировать. Давайте посмотрим на этот кусок кода для создания случайного числа.
function random() private view returns (uint8) { return uint8(uint256(keccak256(block.timestamp, block.difficulty))%251); }
Этот фрагмент кода сначала хэширует временную метку блока и сложность. Затем мы конвертируем хеш в целое число и делим его на 251, чтобы получить целое число от 0 до 250. Однако проблема с этим фрагментом кода заключается в том, что мы не должны доверять майнеру для выбора победителя.
2. Лотерейный ввод — произвольные данные
Нам нужно больше произвольных данных для выбора нашего победителя. Мы можем использовать адреса игроков, которые заключили наш умный контракт с лотереей, но мы должны скрывать это от других игроков, поскольку они могут злоупотреблять им. Скрытие этой информации невозможно, поскольку все это записано в блокчейне.
Можно использовать числа, указанные в нашем умном договоре лотереи. Пользователи должны хешировать номер, который они выбирают вместе с их адресом Ethereum. Это дает нам довольно случайное число.
3. Другие механизмы
3.1 Эфириум Будильник
Разработчики должны думать о том, когда выбрать победителя. Такие вещи, как время на часах, недоступны на виртуальной машине Ethereum, так как код будет выполняться на нескольких узлах в разное время. Это затрудняет выбор победителя. Один из способов сделать это — внедрить в ваш умный контракт функцию, которая закроет лотерею и выберет победителя. Это не так децентрализовано, как мы хотим. Владелец контракта может закрыть лотерею, когда он уверен, что их друг выиграет. Мы хотим избежать такого рода мошенничества.
Лучшим вариантом является использование Ethereum Alarm Clock. Это сервис, который позволяет планировать транзакции, которые будут выполняться позднее в блокчейне Ethereum. Этот сервис абсолютно не заслуживает доверия, что означает, что весь сервис работает как умный контракт. По сути, Ethereum Alarm Clock использует номер блока для планирования транзакций. Осторожно, это не значит, что контракт просыпается сам по себе. Он полагается на пользователей, имеющих интерес (эфирное вознаграждение) к вызову функции «выбрать победителя». Конечно, если никто не вызывает вашу функцию, ваша лотерея провалится.
3.2 Случайный ввод данных
Random.org предоставляет API, который дает вам случайный источник данных через JSON. Умный контракт Ethereum может использовать этот источник данных для подачи алгоритма, который выбирает случайное число. Поскольку безопасность важна, можно использовать цифровую подпись. Случайные данные будут подписаны Random.org. Вы можете проверить целостность данных, чтобы доказать, что они действительно были получены с Random.org, и данные не были подделаны.
RANDAO — это новый проект в пространстве блокчейнов, который сосредоточен исключительно на предоставлении случайных чисел. Они используют комбинацию оракулов и умных контрактов, чтобы предоставить вам случайные числа. Однако служба RANDAO в настоящее время работает довольно медленно. Это не идеально, если у вас есть приложение, которое часто используется.
3.3 Blocknumber Watcher
Вы также можете использовать наблюдателя в своем коде, который проверяет номер блока, пока он не совпадет с целевым номером, который вы установили.
function f( blocknumber, to_address, value_) { var filter = web3.eth.filter('latest').watch( function(err, blockHash) { var target=blocknumber; if(web3.eth.blockNumber==target) { filter.stopWatching(); // your function here web3.eth.sendTransaction({to:to_address, from:web3.eth.coinbase, value: web3.toWei(value_,"ether")}); filter = null; console.warn('Block reached'); if (callback) return callback(false); else return false; } else { console.log('Waiting the block'); } }); };
3.4 iOlite Smart Создание контрактов
iOlite создает продукт, который принимает естественный язык для создания умных контрактов. Он использует Stanford Natural Language Processing (NLP), который называется Fast Adaptation Engine (FAE). iOlite опирается на обучение сообщества экспертов Solidity. Эксперты по солидности (участники) могут определять структуры, содержащие одно или несколько предложений, и прикреплять их к соответствующему коду смарт-контракта.
Движок Stanford NLP создан для понимания сложного языка. Уровень сложности языка зависит от объема машинного обучения. После соответствующего обучения движок сможет создавать сложные умные контракты. FAE способна создавать такие контракты, поскольку сложный контракт на самом деле не так уж и сложен. Эксперты могут разбить запрос на несколько небольших частей кода и прикрепить его к одному предложению.
Когда кто-то вводит несколько предложений, он ищет соответствующие структуры / предложения для построения «сложного» контракта. Участники будут вознаграждены токенами iOlite в процессе майнинга новых структур.
Преимущество использования iOlite заключается в том, что умные эксперты по контрактам могут решить такие сложные для вас задачи, как генерация случайных чисел. Вы можете найти больше информации на iOlite.io .
Вывод
Как видите, генерировать действительно случайные входные данные непросто. Не полагайтесь на block.timestamp
, now
и block.blockhash
в качестве источника случайности. Хорошее решение включает в себя сочетание нескольких псевдослучайных вводов данных и использование оракулов или умных контрактов для повышения надежности. Вы должны быть на 100% уверены, что никто не сможет изменить данные, вводимые в ваш умный контракт.
Будьте внимательны и дважды подумайте, прежде чем реализовывать логику генерации случайных чисел.