Використання випадкового оракула на прикладі лотереї

Якось вранці на очі потрапила стаття про генераторі випадкових чисел, що перевіряється на блокчейні Waves platform.

Загальна картина була зрозумілою, а ось спосіб конкретної реалізації — ні. Якісь коди, підписи, що куди навіщо?

Декілька консультацій у автора оракула, в результаті вдалося об'єднати логіку розіграшу (реалізована на PHP) з алгоритмом отримання випадкового числа.

  1. У момент старту турніру/раунду ми запитуємо у оракула першу частину коду (R-code).

    У цей момент немає інформації про кількість гравців, про кількість призових місць, про розмір призових виплат і взагалі про існування лотереї. Оракул за допомогою транзакції видає персональний випадковий код, який надалі може бути використаний лише один раз і лише тим, хто його запросив. До речі, R-code можна «закупити» (мається на увазі вартість транзакції запиту + компенсація оракулу за транзакцію у відповідь, це сума порядку $0.015 за поточним курсом, сам код видається безкоштовно) заздалегідь відразу кілька, щоб потім не чекати отримання транзакції у відповідь. Я зробив невеликий регулярно поповнюваний буфер БД.

  2. Турнір триває стандартно 60 блоків блокчейну Waves platform, на даний момент це приблизно 1 година. Турнір вважається таким, що відбувся і закритим, якщо після 60 блоків у ньому буде не менше двох квитків, інакше час активності турніру продовжується на наступні 60 блоків.
  3. Відразу після закриття турніру ми формуємо та відправляємо дату транзакцію (за неї також сплачуємо комісію приблизно $0.005), за потреби — кілька, у якій зафіксовано всі умови розіграшу та впорядкований список гравців (квитків) з якого нам необхідно обрати переможців.
  4. На даному етапі ми вже маємо першу частину коду (R-code) плюс ID дата транзакції (TXID). Ми надсилаємо їх на підпис оракулу у вигляді конкатенації (R-code + TXID), знову сплачуємо комісію + компенсацію. Оракул перевіряє отримані дані на предмет унікальності та належності, а у відповідь посилає нам другу частину коду (S-code) у форматі sha256, яка є відправною точкою для генератора випадкових чисел.
  5. Щоб отримати випадкове число, яке буде вказувати на порядковий номер квитка, що переміг, ми перетворюємо S-code з бінарних даних sha256 в шістнадцяткове (HEX) подання. Потім з HEX рядка, отримуємо число. Отримуємо залишок від ділення числа на квитків (all_tickets) і додаємо до результату 1 (щоб отримати цифру 1 до all_tickets). У підсумку ми маємо порядковий номер переможця.
  6. Якщо за умовами розіграшу переможців декілька, то повторюємо попередні операції у кількості, що дорівнює кількості призових місць. При цьому щоразу видаляємо зі списку квиток, який вже виграв і зменшуємо all_tickets на 1, а замість S-code вказуємо попереднє отримане число.

Розберемо конкретний реальний приклад, турнір №119:

Всього 7 квитків (all_tickets)
Вартість квитка 50 монет (Bet)
Ігровий збір 10% (Fee)

За умов лотереї 30% потрапляють у призові, тобто. у цьому випадку 2 квитки повинні отримати приз, розмір якого вважається за формулою (Bet*all_tickets-Fee)/2.

1. Отримали R-code: RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE

2. Після закриття турніру маємо список квитків у вигляді пар: номер + адреса (адреса гаманця з якої була оплата участі у турнірі). Зауважимо, що адреси можуть повторюватися, це означає, що один учасник купив кілька квитків в один турнір, це не забороняється правилами.

Надіслали дату транзакцію: 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S

3. Запитали S-code: FTF3uRyaa4F2uAyD6z5a3CNbTXbQLc7fSR6CFNVjgZYV з коментарем (R-code + TXID):
RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S

4. Отримали S-code: Ri89jHB4UXZDXY6gT1m4LBDXGMTaYzHozMk4nxiuqVXdC

5. Визначили переможців.

6. Надіслали виплати

У результаті ми маємо у блокчейні покрокову фіксацію процедури розіграшу призів із можливістю перевірити її у будь-який час. Підтасувати результати з боку організатора практично неможливо, принаймні зробити це непомітно не вдасться.

determine the winner № 1

All_tickets:
Index: 1 Ticket:139
Index: 2 Ticket:141
Index: 3 Ticket:143
Index: 4 Ticket:145
Index: 5 Ticket:147
Index: 6 Ticket:149
Index: 7 Ticket:151

1. bin -> hex ( bin2hex(sha256(S-code)) ): Ri89jHB4UXZDXY6gT1m4LBDXGMTaYzHozMk4nxiuqVXdC -> 0xdaf5802953dcb27f89972e38e8900b898733f6a613e6e1c6c5491362c1832596

2. hex -> gmp number: 0xdaf5802953dcb27f89972e38e8900b898733f6a613e6e1c6c5491362c1832596 -> 99037963059744689166154019807924045947962565922868104113173478160267437352342

3. gmp -> modulo (mod=7): 99037963059744689166154019807924045947962565922868104113173478160267437352342 -> 4

4. modulo -> ticket: 4 -> 145

determine the winner № 2

All_tickets:

Index: 1 Ticket:139
Index: 2 Ticket:141
Index: 3 Ticket:143
Index: 4 Ticket:147
Index: 5 Ticket:149
Index: 6 Ticket:151

1. bin -> hex ( bin2hex(sha256(previous hex)) ): daf5802953dcb27f89972e38e8900b898733f6a613e6e1c6c5491362c1832596 -> 0x9560e77525e9ea2db92cdb8484dc52046ccafac7c719b8859ff55f0eb92834a0
2. hex -> gmp number: 0x9560e77525e9ea2db92cdb8484dc52046ccafac7c719b8859ff55f0eb92834a0 -> 67565829218838067182838043983962684143266386786567427968312120473742580659360
3. gmp -> modulo (mod=6): 67565829218838067182838043983962684143266386786567427968312120473742580659360 -> 1
4. modulo -> ticket: 1 -> 139

End.

Джерело: habr.com

Додати коментар або відгук