Używanie losowej wyroczni na przykładzie loterii

Któregoś ranka natknąłem się na artykuł dot weryfikowalny generator liczb losowych na blockchainie platformy Waves.

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.

  1. 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.

  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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: RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE

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: 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S

3. Żądany kod S: FTF3uRyaa4F2uAyD6z5a3CNbTXbQLc7fSR6CFNVjgZYV z komentarzem (kod R + TXID):
RdbAiAhKhveAtR4eyTKq75noMxdcEoxbE6BvojJjM13VE 82JTMzhHM5xEA2fQ9Qscd5QAJU3DAd8nShLjdVHTer5S

4. Otrzymany kod S: Ri89jHB4UXZDXY6gT1m4LBDXGMTaYzHozMk4nxiuqVXdC

5. Wyłoniono zwycięzców.

6. Wysłane płatności

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

Dodaj komentarz