Któregoś ranka natknąłem się na artykuł dot
Ogólny obraz był jasny, ale konkretna metoda wdrożenia nie. Jakieś kody, podpisy, co, gdzie, dlaczego?
Dzięki kilku konsultacjom z autorem wyroczni udało się połączyć logikę rysowania (zaimplementowaną w PHP) z algorytmem uzyskiwania liczby losowej.
- Na początku turnieju/rundy prosimy o pierwszą część kodu (kod R) od wyroczni.
W tej chwili nie ma żadnych informacji na temat liczby graczy, liczby miejsc z nagrodami, wielkości wypłat nagród ani ogólnie o istnieniu loterii. Wyrocznia poprzez transakcję wydaje osobisty losowy kod, który może zostać użyty tylko raz i tylko przez tych, którzy o to poproszą. Swoją drogą R-code można „kupić” (co oznacza koszt transakcji żądania + rekompensata dla wyroczni za transakcję odpowiedzi, jest to kwota około 0.015 USD według aktualnego kursu, sam kod wydawany jest bezpłatnie ) z kilkukrotnym wyprzedzeniem, aby nie czekać później na otrzymanie odpowiedzi transakcji. Zrobiłem mały, regularnie aktualizowany bufor w bazie danych.
- Turniej trwa zazwyczaj 60 bloków blockchainu platformy Waves, obecnie trwa około 1 godziny. Turniej uważa się za zakończony i zamknięty, jeśli po 60 blokach znajdują się w nim co najmniej dwa bilety, w przeciwnym razie czas aktywności turnieju wydłuża się o kolejne 60 bloków.
- Zaraz po zakończeniu turnieju generujemy i wysyłamy transakcję terminową (za nią płacimy także prowizję w wysokości około 0.005 $), w razie potrzeby kilka, w której zapisywane są wszystkie warunki losowania oraz uporządkowana lista graczy (bilety) spośród których musimy wybrać zwycięzców.
- Na tym etapie mamy już pierwszą część kodu (R-code) plus identyfikator daty transakcji (TXID). Wysyłamy je do podpisu do Oracle w formie konkatenacji (R-code + TXID), ponownie płacimy prowizję + wynagrodzenie. Wyrocznia sprawdza otrzymane dane pod kątem unikalności i przynależności, a w odpowiedzi przesyła nam drugą część kodu (S-code) w formacie sha256, który jest punktem wyjścia dla generatora liczb losowych.
- Aby otrzymać liczbę losową, która będzie wskazywała numer kolejny zwycięskiego losu, konwertujemy kod S z danych binarnych sha256 na reprezentację szesnastkową (HEX). Następnie z powstałego ciągu HEX otrzymujemy liczbę. Pozostałą część wyniku dzielimy przez liczbę biletów (all_tickets) i do wyniku dodajemy 1 (aby otrzymać liczbę 1 przed all_tickets). W rezultacie otrzymujemy numer seryjny zwycięzcy.
- Jeżeli zgodnie z warunkami losowania zwycięzców będzie kilku, wówczas powtarzamy poprzednie operacje w ilości równej liczbie miejsc nagród. W takim przypadku za każdym razem usuwamy z listy bilet, który już został wygrany i zmniejszamy all_tickets o 1, a zamiast S-code podajemy poprzednio otrzymany numer.
Spójrzmy na konkretny, prawdziwy przykład, turniej nr 119:
Łącznie 7 biletów (all_tickets)
Bilet kosztuje 50 monet (zakład)
Opłata za grę 10% (Opłata)
Zgodnie z warunkami loterii 30% trafia do nagrody pieniężnej, tj. w tym przypadku 2 bilety muszą otrzymać nagrodę, której wysokość obliczana jest według wzoru (Bet*all_tickets-Fee)/2.
1. Otrzymany kod R:
2. Po zakończeniu turnieju dysponujemy listą biletów w postaci par: numer + adres (adres portfela, z którego została dokonana płatność za udział w turnieju). Należy pamiętać, że adresy mogą się powtarzać, co oznacza, że jeden uczestnik kupił kilka biletów na jeden turniej, czego regulamin nie zabrania.
Data wysłania transakcji:
3. Żądany kod S:
RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S
4. Otrzymany kod S:
5. Wyłoniono zwycięzców.
Dzięki temu mamy w blockchainie zapis krok po kroku przebiegu losowania nagrody z możliwością sprawdzenia go w każdej chwili. Manipulacja wynikami przez organizatora jest prawie niemożliwa, a przynajmniej nie będzie już możliwa niezauważona.
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.
Źródło: www.habr.com