Es gibt ein Problem - es ist schwierig, eine Zufallszahl in einem dezentralen Netzwerk zu generieren. Fast alle Blockchains sind bereits darauf gestoßen. In Netzwerken, in denen kein Vertrauen zwischen Benutzern besteht, löst die Erstellung einer unbestreitbaren Zufallszahl viele Probleme.
Der Artikel beschreibt, wie das Problem am Beispiel von Spielen gelöst werden kann. Der erste davon war der
Waves Xmas Tree . Für die Entwicklung brauchten wir einen Zufallszahlengenerator.

Zunächst wollten wir eine Nummer basierend auf Informationen aus der Blockchain generieren. Dann wurde jedoch klar: Die Nummer konnte manipuliert werden, was bedeutet, dass die Lösung nicht passt.
Wir haben eine Problemumgehung gefunden: Verwenden Sie das Commit-Disclosure-Schema. Der Server hat eine Zahl von 1 bis 5 „erraten“, „Salz“ hinzugefügt und dann das Ergebnis mithilfe
der Keccak-Funktion gehasht. Der Server hat einen Smart-Vertrag mit einer bereits gespeicherten Nummer vorab bereitgestellt. Es stellt sich heraus, dass das Spiel auf die Tatsache reduziert wurde, dass der Benutzer die durch den Hash verborgene Zahl erraten hat.
Der Spieler machte eine Wette und der Server schickte die angeforderte Nummer und das "Salz" an den Smart-Vertrag. Im Klartext enthüllte er die Karten. Danach überprüfte der Server die Zahlen und entschied, ob der Benutzer gewonnen oder verloren hatte.
Wenn der Server keine Nummer oder "Salt" zur Überprüfung gesendet hat, hat der Benutzer gewonnen. In diesem Fall war es für jedes Spiel erforderlich, im Voraus einen intelligenten Vertrag bereitzustellen und potenzielle Gewinne darin zu platzieren. Es stellte sich als unpraktisch, lang und teuer heraus. Zu diesem Zeitpunkt gab es keine andere sichere Lösung.
Vor kurzem hat das Tradisys-Team vorgeschlagen, die Funktion
rsaVerify () zum Waves-Protokoll hinzuzufügen. Es überprüft die Gültigkeit der RSA-Signatur basierend auf dem öffentlichen und privaten Schlüssel. Als Ergebnis wurde die Funktion hinzugefügt.
Wir haben drei Spiele entwickelt:
Dice Roller ,
Coin Flip und
Ride On Waves . Jede implementierte Zufallszahlentechnologie. Mal sehen, wie es funktioniert.

Betrachten Sie die Zufallszahlengenerierung am Beispiel von Ride on Waves. Einen intelligenten Vertrag finden Sie
hier .
Gehen Sie zur Registerkarte
Skript und wählen Sie
Dekompiliert . Siehe den Code des Smart Contract (auch bekannt als Script).

Der Smart Contract Code enthält eine Reihe von Funktionen. Die als @Callable gekennzeichneten können mithilfe von Aufruftransaktionen ausgelöst werden. Wir sind an zwei Funktionen interessiert:
Wetten und
Abheben :
- Funkwette (playerChoice)
- func zurückziehen (gameId, rsaSign)
1. Der Benutzer wählt die Länge des Segments und die Größe des Einsatzes.

2. Der Kunde bildet eine Wettfunktion. Für das obige Bild wird dies
gewettet ("50") .
3. Der Client sendet die Invocation-Transaktion an die Adresse des Smart Contract (Broadcast InvocationTx). Eine Transaktion als Call-Parameter enthält die Wettfunktion. Dies bedeutet, dass die Invocation-Transaktion die Ausführung der Wettfunktion (Auswahl: String) für den Smart-Vertrag startet.

4. Betrachten Sie die Wettfunktion:
@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))) } }
Die Funktion schreibt ein neues Spiel in den Smart Contract State. Nämlich:
- Eindeutige Kennung für ein neues Spiel (Spiel-ID)
- Spielstatus = ABGEGEBEN
- Spielerauswahl (Zeilenlänge 50)
- Öffentlicher Schlüssel
- Mögliche Gewinne (abhängig von der Wette des Spielers)

So sieht der Datensatz in der Blockchain aus (Schlüsselwert):
{ "type": "string", "value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229", "key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx" }
"Key" (Schlüssel) -
Spiel-ID des neuen Spiels. Die restlichen Daten sind in der Zeile des Feldes „Wert“ (Wert) enthalten. Diese Einträge werden auf der Registerkarte
Daten des Smart-Vertrags gespeichert:


5. Der Server „schaut“ sich den Smart-Vertrag an und findet die gesendete Transaktion (neues Spiel) mithilfe der Blockchain-API. Die Spiel-ID des neuen Spiels ist bereits in der Blockchain aufgezeichnet, sodass es nicht mehr möglich ist, sie zu ändern oder zu beeinflussen
6. Der Server bildet eine Rückzugsfunktion (gameId, rsaSign). Zum Beispiel:
withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")
7. Der Server sendet die Invocation-Transaktion an den Smart Contract (Broadcast InvocationTx). Die Transaktion enthält einen Aufruf der generierten Rückzugsfunktion (gameId, rsaSign):

Die Funktion enthält die
Spiel-ID des neuen Spiels und das Ergebnis der RSA-Signatur der eindeutigen Kennung mit einem privaten Schlüssel. Das Ergebnis der Signatur bleibt unverändert.
Was bedeutet das?Wir nehmen den gleichen Wert (Spiel-ID) und wenden die RSA-Signaturmethode darauf an. Wir werden immer das gleiche Ergebnis erzielen. So funktioniert der RSA-Algorithmus. Sie können die endgültige Nummer nicht manipulieren, da die Spiel-ID und das Ergebnis der Verwendung von RSA nicht bekannt sind. Das Abgleichen einer Zahl ist ebenfalls sinnlos.
8. Die Blockchain akzeptiert die Transaktion. Es führt die Rückzugsfunktion aus (gameId, rsaSign)
9. Innerhalb der Rückzugsfunktion wird die
GenerateRandInt-Funktion (gameId, rsaSign) exportiert. Dies ist ein Zufallszahlengenerator
# @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 - und es gibt eine Zufallszahl.
Zunächst wird eine Zeichenfolge erstellt, die das Ergebnis der RSA-Signatur der
Spiel-ID mit dem privaten Schlüssel (
rsaSign ) ist. Es wird dann mit SHA-256 (
sha256 (rsaSign) ) gehasht.
Wir können das Ergebnis der Signatur und des anschließenden Hashings nicht vorhersagen. Daher ist es unmöglich, die Erzeugung einer Zufallszahl zu beeinflussen. Um eine Zahl in einem bestimmten Bereich zu erhalten (z. B. von 1 bis 100), wird die Konvertierungsfunktion toInt und% 100 verwendet (analog zu
mod ).
Am Anfang des Artikels haben wir die Funktion
rsaVerify () erwähnt , mit der Sie die Gültigkeit von RSA-Signaturen mit einem privaten Schlüssel mithilfe eines öffentlichen Schlüssels überprüfen können. Hier ist der Teil GenerateRandInt (gameId, rsaSign):
rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
Der öffentliche RSAPUBLIC-Schlüssel und die rsaSign-Zeichenfolge werden an die Eingabe übergeben. Die Unterschrift wird auf Gültigkeit geprüft. Bei erfolgreicher Prüfung wird eine Nummer generiert. Andernfalls ist das System der Ansicht, dass die Signatur ungültig ist (ungültige RSA-Signatur).
Der Server muss die Spiel-ID mit dem privaten Schlüssel signieren und innerhalb von 2880 Blöcken eine gültige Rsa-Signatur senden. Der Parameter wird beim Bereitstellen eines Smart Contract konfiguriert. Wenn während der zugewiesenen Zeit nichts passiert, gewinnt der Benutzer. In diesem Fall muss der Preis selbst an Ihre Adresse gesendet werden. Es stellt sich heraus, dass der Server "nicht rentabel zu betrügen" ist, da dies zu einem Verlust führt. Unten ist ein Beispiel.

Benutzer spielt
Dice Roller . Ich habe 2 von 6 Flächen des Würfels ausgewählt, die Wette beträgt 14 WELLEN. Wenn der Server innerhalb der festgelegten Zeit (2880 Blöcke) keine gültige RSA-Signatur für den Smart-Vertrag sendet, nimmt der Benutzer 34,44 WAVES.
Um Zahlen in Spielen zu generieren, verwenden wir das Orakel - ein externes, nicht blockierendes System. Der Server implementiert die RSA-Signatur der Spiel-ID. Der Smart-Vertrag überprüft die Gültigkeit der Unterschrift und ermittelt den Gewinner. Wenn der Server nichts gesendet hat, gewinnt der Benutzer automatisch.
Das beschriebene Verfahren stellt sicher, dass eine Manipulation technisch unmöglich ist. Alle Tradisys-Spiele verwenden einen Algorithmus, daher sind sie ehrlich und transparent. Alles eignet sich für die öffentliche Kontrolle. Dies sorgt für Ehrlichkeit.