Obstaja težava: v decentraliziranem omrežju je težko ustvariti naključno število. Skoraj vse verige blokov so se že srečale s to težavo. Navsezadnje v omrežjih, kjer ni zaupanja med uporabniki, ustvarjanje neizpodbitnega naključnega števila reši številne težave.
V tem članku bomo na primeru iger razložili, kako smo rešili problem. Prva od teh je bila Za razvoj smo potrebovali generator naključnih števil.

Sprva smo načrtovali generiranje številke na podlagi podatkov verige blokov. Vendar je kasneje postalo jasno, da bi številka lahko bila ponarejena, zaradi česar je ta rešitev neprimerna.
Našli smo rešitev: uporabo sheme »commit-reveal«. Strežnik bi uganil število med 1 in 5, mu dodal sol in nato rezultat zgostil z uporabo Strežnik je namestil pametno pogodbo s predhodno shranjeno številko. Igra se je torej skrčila na to, da je uporabnik uganil številko, skrito v zgoščevalni vrednosti.
Igralec je stavil, strežnik pa je poslal številko in "sol" pametni pogodbi. Preprosto povedano, šlo je za obračun kart. Strežnik je nato primerjal številke in odločil, ali je igralec zmagal ali izgubil.
Če strežnik ni poslal številke ali »soli« za preverjanje, je uporabnik zmagal. V tem primeru je vsaka igra zahtevala vnaprejšnjo namestitev pametne pogodbe in programiranje potencialnih dobitkov vanjo. To se je izkazalo za neprijetno, zamudno in drago. Takrat ni bilo druge varne rešitve.
Nedavno je ekipa Tradisys predlagala dodajanje funkcije protokolu Waves rsaVerify()Preveri veljavnost podpisa RSA na podlagi javnega in zasebnega ključa. Funkcija je bila sčasoma dodana.
Razvili smo tri igre: , и Vsak od njih uporablja tehnologijo generiranja naključnih števil. Poglejmo, kako deluje.

Oglejmo si generiranje naključnih števil na primeru Ride on Waves. Pametno pogodbo lahko najdete .
Pojdite na zavihek Script in izberite DekompiliranoVideli boste kodo pametne pogodbe (oz. skript).

Koda pametne pogodbe vsebuje nabor funkcij. Tiste, ki so označene kot @Callable, je mogoče poklicati z uporabo Transakcije klicanjaZanimata nas dve funkciji: stavil и umaknejo:
- stava funkcije (izbira igralca)
- func umakni(gameId,rsaSign)
1. Uporabnik izbere dolžino segmenta in velikost stave.

2. Stranka generira funkcijo stave. Za zgornjo sliko bi to bilo stava («50»).
3. Odjemalec pošlje transakcijo Invocation na naslov pametne pogodbe (oddajanje InvocationTx). Transakcija vsebuje funkcijo stave kot parameter Call. To pomeni, da transakcija Invocation sproži izvajanje funkcije stave (izbira: String) na pametni pogodbi.

4. Oglejmo si funkcijo stave:
@Callable(i)
func bet (playerChoice) = {
let newGameNum = IncrementGameNum()
let gameId = toBase58String(i.transactionId)
let pmt = extract(i.payment)
let betNotInWaves = isDefined(pmt.assetId)
let feeNotInWaves = isDefined(pmt.assetId)
let winAmt = ValidateBetAndDefineWinAmt(pmt.amount, playerChoice)
let txIdUsed = isDefined(getString(this, gameId))
if (betNotInWaves)
then throw ("Bet amount must be in Waves")
else if (feeNotInWaves)
then throw ("Transaction's fee must be in Waves")
else if (txIdUsed)
then throw ("Passed txId had been used before. Game aborted.")
else {
let playerPubKey58 = toBase58String(i.callerPublicKey)
let gameDataStr = FormatGameDataStr(STATESUBMITTED, playerChoice, playerPubKey58, height, winAmt, "")
ScriptResult(WriteSet(cons(DataEntry(RESERVATIONKEY, ValidateAndIncreaseReservedAmt(winAmt)), cons(DataEntry(GAMESCOUNTERKEY, newGameNum), cons(DataEntry(gameId, gameDataStr), nil)))), TransferSet(cons(ScriptTransfer(SERVER, COMMISSION, unit), nil)))
}
}Funkcija zapiše novo igro v stanje pametne pogodbe. Natančneje:
- Enolični identifikator nove igre (ID igre)
- Stanje igre = POSLANO
- Izbira igralca (dolžina segmenta 50)
- Javni ključ
- Potencialni dobitki (odvisno od igralčeve stave)

Takole izgleda vnos podatkov v verigo blokov (ključ-vrednost):
{
"type": "string",
"value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229",
"key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx"
}"Ključ" - ID igre nova igra. Preostali podatki so v vrstici polja »vrednost«. Ti zapisi so shranjeni v zavihku datum pametna pogodba:


5. Strežnik »pregleda« pametno pogodbo in z uporabo API-ja verige blokov poišče poslano transakcijo (novo igro). ID nove igre je že zabeležen v verigi blokov, kar pomeni, da ga ni več mogoče spremeniti ali nanj vplivati.
6. Strežnik generira funkcijo za izplačilo (gameId, rsaSign). Na primer takole:
withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")7. Strežnik pošlje transakcijo Invocation pametni pogodbi (oddajanje InvocationTx). Transakcija vsebuje klic generirane funkcije za izplačilo (gameId, rsaSign):

Funkcija vsebuje ID igre nova igra in rezultat RSA podpisa edinstvenega identifikatorja z zasebnim ključem. Rezultat podpisa je nespremenljiv.
Kaj to pomeni?
Vzamemo isto vrednost (ID igre) in nanjo uporabimo metodo podpisa RSA. Vedno bomo dobili enak rezultat. Tako deluje algoritem RSA. Končne številke ni mogoče manipulirati, saj ID igre in rezultat uporabe RSA nista znana. Izbira številke je prav tako nesmiselna.
8. Blockchain sprejme transakcijo. Sproži funkcijo izplačila (gameId, rsaSign)
9. Znotraj funkcije umika se izvede odstranitev Funkcije GenerateRandInt (gameId, rsaSign). To je generator naključnih števil.
# @return 1 ... 100
func GenerateRandInt (gameId,rsaSign) = {
# verify RSA signature to proof random
let rsaSigValid = rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
if (rsaSigValid)
then {
let rand = (toInt(sha256(rsaSign)) % 100)
if ((0 > rand))
then ((-1 * rand) + 1)
else (rand + 1)
}
else throw ("Invalid RSA signature")
}rand – in obstaja naključno število.
Najprej se vzame niz, ki je rezultat podpisa RSA ID igre zasebni ključ (rsaSign). Nato zgoščeno z uporabo SHA-256 (sha256(rsaSign)).
Rezultata podpisa in poznejšega zgoščevanja ne moremo predvideti. Zato je nemogoče vplivati na generiranje naključnega števila. Za pridobitev števila v določenem območju (na primer od 1 do 100) uporabimo funkcijo pretvorbe toInt in %100 (analogno ).
Na začetku članka smo omenili funkcijo rsaVerify(), ki vam omogoča preverjanje veljavnosti podpisa RSA z uporabo zasebnega ključa v primerjavi z javnim ključem. Tukaj je del GenerateRandInt(gameId,rsaSign):
rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)Javni ključ RSAPUBLIC in niz rsaSign se podajata kot vhod. Preveri se veljavnost podpisa. Če je preverjanje uspešno, se ustvari številka. V nasprotnem primeru sistem podpis šteje za neveljavnega (neveljaven podpis RSA).
Strežnik mora podpisati ID igre z zasebnim ključem in poslati veljaven podpis RSA v 2880 blokih. Ta parameter se konfigurira med uvajanjem pametne pogodbe. Če se v določenem času nič ne zgodi, uporabnik zmaga. V tem primeru je treba nagrado poslati na njegov naslov ročno. Zato goljufanje ni v najboljšem interesu strežnika, saj to vodi v izgubo. Spodaj je primer.

Uporabnik se igra Izbrani 2 od 6 strani kocke, stavite 14 VALOV. Če strežnik ne pošlje veljavnega podpisa RSA za pametno pogodbo v določenem času (2880 blokov), bo uporabnik vzel 34.44 VALOV.
Za generiranje številk v igrah uporabljamo orakelj – zunanji sistem, ki ne uporablja tehnologije veriženja blokov. Strežnik izvede podpis RSA na ID-ju igre. Pametna pogodba preveri veljavnost podpisa in določi zmagovalca. Če strežnik ne pošlje ničesar, uporabnik samodejno zmaga.
To je poštena metoda generiranja, saj je manipulacija tehnično nemogoča. Vse igre Tradisys delujejo na podlagi opisanega algoritma. Tako delujejo igre veriženja blokov. Vse je pregledno in preverljivo. Nobena druga veriga blokov nima podobnega sistema. Gre za pošteno naključnost.
Vir: www.habr.com
