Разработка системы RNG (Random Number Generator) на блокчейне

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы RNG (Random Number Generator) на блокчейне
Средняя
от 1 рабочего дня до 3 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы RNG (Random Number Generator) на блокчейне

block.timestamp, block.prevrandao, хэш предыдущего блока — всё это уже пробовали использовать как источники случайности. И всё это небезопасно: майнер или валидатор может влиять на эти значения в своих интересах. В 2019 году смарт-контракт лотереи потерял $4M — атакующий контролировал несколько пулов и мог выбирать, когда отправлять транзакцию, манипулируя блочным хэшем. Случайные числа на блокчейне — нетривиальная задача, которая решается по-разному в зависимости от threat model.

Почему on-chain рандом сложен

Блокчейн детерминирован. Каждый узел должен прийти к одному результату, выполняя одни и те же операции. Это фундаментально противоречит случайности: если результат предсказуем — он не случаен. Любой источник, который виден в блокчейне до фиксации результата, может быть использован атакующим.

Validator bias — валидатор на Ethereum видит block.prevrandao (RANDAO reveal) до публикации блока. Если результат невыгоден — он может пропустить свой слот (слот пропускается, результат меняется). Стоимость атаки = потерянное вознаграждение за слот (~0.01 ETH). Если ставка в лотерее > 0.01 ETH — атака рациональна.

Chainlink VRF: стандарт для большинства случаев

Chainlink VRF (Verifiable Random Function) — наиболее проверенное решение для NFT-минта, лотерей, игровой механики. Работает через оракульную сеть:

  1. Контракт запрашивает случайное число, отправляя LINK
  2. Chainlink-нода генерирует случайное число и криптографическое доказательство
  3. Доказательство верифицируется on-chain перед использованием числа
// VRF V2.5 (актуальная версия)
import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";

contract Lottery is VRFConsumerBaseV2Plus {
    uint256 public s_subscriptionId;
    bytes32 public keyHash; // gas lane
    uint32 public callbackGasLimit = 200_000;
    uint16 public requestConfirmations = 3;
    
    mapping(uint256 => address) public requestToPlayer;
    
    function requestRandomWinner() external returns (uint256 requestId) {
        requestId = s_vrfCoordinator.requestRandomWords(
            VRFV2PlusClient.RandomWordsRequest({
                keyHash: keyHash,
                subId: s_subscriptionId,
                requestConfirmations: requestConfirmations,
                callbackGasLimit: callbackGasLimit,
                numWords: 1,
                extraArgs: VRFV2PlusClient._argsToBytes(
                    VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
                )
            })
        );
        requestToPlayer[requestId] = msg.sender;
    }
    
    function fulfillRandomWords(
        uint256 requestId,
        uint256[] calldata randomWords
    ) internal override {
        address player = requestToPlayer[requestId];
        uint256 result = randomWords[0] % totalTickets;
        _declareWinner(player, result);
    }
}

requestConfirmations: 3 — ждём 3 блока подтверждения перед генерацией. Это усложняет reorg-атаки на request.

Ограничения VRF: latency 1-3 блока (15-45 секунд на mainnet), стоимость LINK на каждый запрос (0.25-2 LINK в зависимости от сети), необходимость subscription менеджмента. Для high-frequency gameplays (каждый ход в игре требует рандома) — слишком дорого и медленно.

Commit-reveal: рандом без оракула

Для случаев без доступа к Chainlink или при необходимости минимизировать затраты — commit-reveal схема:

Фаза commit: каждый участник публикует keccak256(secret, address). Secret хранится off-chain.

Фаза reveal: участники раскрывают secret. XOR всех secrets = итоговое случайное число.

mapping(address => bytes32) public commits;
mapping(address => uint256) public reveals;
uint256 public combinedRandom;

function commit(bytes32 commitment) external {
    commits[msg.sender] = commitment;
}

function reveal(uint256 secret) external {
    require(keccak256(abi.encode(secret, msg.sender)) == commits[msg.sender]);
    reveals[msg.sender] = secret;
    combinedRandom ^= secret; // XOR всех reveals
}

Слабое место commit-reveal: последний, кто раскрывает secret, видит финальный результат до публикации. Он может выбрать не раскрывать (griefing) или раскрыть только если результат выгоден. Mitigation: штраф за не-reveal (bond при commit, который сгорает при неявке).

RANDAO: нативный Ethereum рандом после Merge

После перехода на PoS Ethereum предоставляет block.prevrandao — агрегированный RANDAO reveal от валидаторов. Это лучше, чем старый block.difficulty, но имеет описанную выше проблему validator bias.

Для некритичных применений (косметика в игре, порядок в очереди, некрупные лотереи) — block.prevrandao достаточен и бесплатен:

uint256 random = uint256(keccak256(abi.encode(
    block.prevrandao,
    block.timestamp,
    msg.sender,
    nonce++
)));

Добавление msg.sender и nonce увеличивает entropy и усложняет предсказание для конкретного пользователя, хотя не устраняет validator bias.

Выбор решения под задачу

Применение Ставка / ценность Рекомендация
NFT минт (whitelist рандом) Высокая Chainlink VRF
Лотерея с крупным призом Высокая Chainlink VRF + requestConfirmations: 5+
Внутриигровой рандом (предметы) Средняя Commit-reveal или Chainlink VRF
Порядок в очереди Низкая block.prevrandao
PvP матчмейкинг Низкая block.prevrandao + nonce

Гибридные решения

Для gamefi-проектов, где требуется быстрый рандом с высокой throughput, используем off-chain VRF с on-chain commitment:

  1. Backend генерирует seed через Chainlink VRF заранее
  2. Hash seed публикуется on-chain (commitment)
  3. При каждом игровом событии — используем HMAC(seed, event_id) как рандом
  4. После сессии — раскрываем seed, пользователи могут верифицировать все результаты

Это даёт instant response на каждое действие и полную верифицируемость постфактум.

Процесс работы

Аналитика. Определяем threat model: кто может атаковать? Какова максимальная выгода от манипуляции? Какая latency допустима? Есть ли доступ к Chainlink на целевом чейне?

Разработка и тестирование. VRFConsumer тестируем через VRFCoordinatorV2_5Mock из пакета Chainlink — позволяет симулировать fulfillment в unit-тестах без реальной оракульной сети. Commit-reveal тестируем на сценарии griefing и last-revealer атак.

Деплой. Для Chainlink VRF — создаём subscription, фондируем LINK, добавляем consumer. Настраиваем мониторинг баланса subscription.

Ориентиры по срокам

Интеграция Chainlink VRF в существующий контракт: 1-2 дня. Система RNG с commit-reveal и anti-griefing: 1-2 дня. Гибридный off-chain VRF с on-chain commitment и верификацией: 3-5 дней.