Якось вранці на очі потрапила стаття про
Загальна картина була зрозумілою, а ось спосіб конкретної реалізації — ні. Якісь коди, підписи, що куди навіщо?
Декілька консультацій у автора оракула, в результаті вдалося об'єднати логіку розіграшу (реалізована на PHP) з алгоритмом отримання випадкового числа.
- У момент старту турніру/раунду ми запитуємо у оракула першу частину коду (R-code).
У цей момент немає інформації про кількість гравців, про кількість призових місць, про розмір призових виплат і взагалі про існування лотереї. Оракул за допомогою транзакції видає персональний випадковий код, який надалі може бути використаний лише один раз і лише тим, хто його запросив. До речі, R-code можна «закупити» (мається на увазі вартість транзакції запиту + компенсація оракулу за транзакцію у відповідь, це сума порядку $0.015 за поточним курсом, сам код видається безкоштовно) заздалегідь відразу кілька, щоб потім не чекати отримання транзакції у відповідь. Я зробив невеликий регулярно поповнюваний буфер БД.
- Турнір триває стандартно 60 блоків блокчейну Waves platform, на даний момент це приблизно 1 година. Турнір вважається таким, що відбувся і закритим, якщо після 60 блоків у ньому буде не менше двох квитків, інакше час активності турніру продовжується на наступні 60 блоків.
- Відразу після закриття турніру ми формуємо та відправляємо дату транзакцію (за неї також сплачуємо комісію приблизно $0.005), за потреби — кілька, у якій зафіксовано всі умови розіграшу та впорядкований список гравців (квитків) з якого нам необхідно обрати переможців.
- На даному етапі ми вже маємо першу частину коду (R-code) плюс ID дата транзакції (TXID). Ми надсилаємо їх на підпис оракулу у вигляді конкатенації (R-code + TXID), знову сплачуємо комісію + компенсацію. Оракул перевіряє отримані дані на предмет унікальності та належності, а у відповідь посилає нам другу частину коду (S-code) у форматі sha256, яка є відправною точкою для генератора випадкових чисел.
- Щоб отримати випадкове число, яке буде вказувати на порядковий номер квитка, що переміг, ми перетворюємо S-code з бінарних даних sha256 в шістнадцяткове (HEX) подання. Потім з HEX рядка, отримуємо число. Отримуємо залишок від ділення числа на квитків (all_tickets) і додаємо до результату 1 (щоб отримати цифру 1 до all_tickets). У підсумку ми маємо порядковий номер переможця.
- Якщо за умовами розіграшу переможців декілька, то повторюємо попередні операції у кількості, що дорівнює кількості призових місць. При цьому щоразу видаляємо зі списку квиток, який вже виграв і зменшуємо all_tickets на 1, а замість S-code вказуємо попереднє отримане число.
Розберемо конкретний реальний приклад, турнір №119:
Всього 7 квитків (all_tickets)
Вартість квитка 50 монет (Bet)
Ігровий збір 10% (Fee)
За умов лотереї 30% потрапляють у призові, тобто. у цьому випадку 2 квитки повинні отримати приз, розмір якого вважається за формулою (Bet*all_tickets-Fee)/2.
1. Отримали R-code:
2. Після закриття турніру маємо список квитків у вигляді пар: номер + адреса (адреса гаманця з якої була оплата участі у турнірі). Зауважимо, що адреси можуть повторюватися, це означає, що один учасник купив кілька квитків в один турнір, це не забороняється правилами.
Надіслали дату транзакцію:
3. Запитали S-code:
RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S
4. Отримали S-code:
5. Визначили переможців.
У результаті ми маємо у блокчейні покрокову фіксацію процедури розіграшу призів із можливістю перевірити її у будь-який час. Підтасувати результати з боку організатора практично неможливо, принаймні зробити це непомітно не вдасться.
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