Υπάρχει ένα πρόβλημα - είναι δύσκολο να δημιουργηθεί ένας τυχαίος αριθμός σε ένα αποκεντρωμένο δίκτυο. Σχεδόν όλα τα blockchain το έχουν ήδη αντιμετωπίσει. Πράγματι, σε δίκτυα όπου δεν υπάρχει εμπιστοσύνη μεταξύ των χρηστών, η δημιουργία ενός αναμφισβήτητου τυχαίου αριθμού λύνει πολλά προβλήματα.
Σε αυτό το άρθρο σας λέμε πώς καταφέραμε να λύσουμε το πρόβλημα χρησιμοποιώντας ως παράδειγμα παιχνίδια. Το πρώτο από αυτά ήταν
Αρχικά, σχεδιάζαμε να δημιουργήσουμε έναν αριθμό με βάση πληροφορίες από το blockchain. Ωστόσο, στη συνέχεια έγινε σαφές: ο αριθμός θα μπορούσε να χειραγωγηθεί, πράγμα που σημαίνει ότι η λύση δεν είναι κατάλληλη.
Καταλήξαμε σε μια λύση: χρησιμοποιήστε το σχήμα δέσμευσης-επέκτασης. Ο διακομιστής μάντεψε έναν αριθμό από το 1 έως το 5, πρόσθεσε ένα αλάτι σε αυτόν και στη συνέχεια κατακερματίστηκε το αποτέλεσμα χρησιμοποιώντας
Ο παίκτης έβαλε ένα στοίχημα και ο διακομιστής έστειλε τον κρυφό αριθμό και το "αλάτι" στο έξυπνο συμβόλαιο. Με απλά λόγια, αποκάλυψε τα χαρτιά. Μετά από αυτό, ο διακομιστής έλεγξε τους αριθμούς και αποφάσισε αν ο χρήστης κέρδισε ή έχασε.
Εάν ο διακομιστής δεν έστειλε έναν αριθμό ή "αλάτι" για επαλήθευση, ο χρήστης κέρδισε. Σε αυτήν την περίπτωση, για κάθε παιχνίδι ήταν απαραίτητο να αναπτυχθεί ένα έξυπνο συμβόλαιο εκ των προτέρων και να συμπεριληφθούν πιθανά κέρδη σε αυτό. Αποδείχθηκε ότι ήταν άβολο, χρονοβόρο και ακριβό. Τότε δεν υπήρχε άλλη ασφαλής λύση.
Πρόσφατα, η ομάδα Tradisys πρότεινε την προσθήκη μιας συνάρτησης στο πρωτόκολλο Waves rsaVerify(). Ελέγχει την εγκυρότητα της υπογραφής RSA με βάση το δημόσιο και ιδιωτικό κλειδί. Ως αποτέλεσμα, προστέθηκε η δυνατότητα.
Έχουμε αναπτύξει τρία παιχνίδια:
Ας δούμε τη δημιουργία ενός τυχαίου αριθμού χρησιμοποιώντας το Ride on Waves ως παράδειγμα. Το έξυπνο συμβόλαιο μπορεί να βρεθεί
Μεταβείτε στην καρτέλα Γραφή και επιλέξτε Απομεταγλωττισμένο. Θα δείτε τον κωδικό έξυπνου συμβολαίου (γνωστός και ως σενάριο).
Ο κωδικός έξυπνου συμβολαίου περιέχει ένα σύνολο λειτουργιών. Αυτά που έχουν επισημανθεί ως @Callable μπορούν να εκκινηθούν χρησιμοποιώντας Συναλλαγές επίκλησης. Μας ενδιαφέρουν δύο λειτουργίες: στοίχημα и αποσύρω:
- στοίχημα func (playerChoice)
- απόσυρση func (gameId,rsaSign)
1. Ο χρήστης επιλέγει το μήκος του τμήματος και το μέγεθος του στοιχήματος.
2. Ο πελάτης δημιουργεί μια συνάρτηση στοιχήματος. Για την παραπάνω εικόνα θα ήταν στοίχημα ("50").
3. Ο πελάτης στέλνει μια συναλλαγή Invocation στη διεύθυνση έξυπνου συμβολαίου (broadcast InvocationTx). Η συναλλαγή περιέχει τη συνάρτηση στοιχήματος ως παράμετρο κλήσης. Αυτό σημαίνει ότι η συναλλαγή Invocation ενεργοποιεί την εκτέλεση της συνάρτησης στοιχήματος (επιλογή: String) στο έξυπνο συμβόλαιο.
4. Εξετάστε τη συνάρτηση στοιχήματος:
@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)))
}
}
Η συνάρτηση γράφει ένα νέο παιχνίδι στην κατάσταση του έξυπνου συμβολαίου. Και συγκεκριμένα:
- Μοναδικό αναγνωριστικό για ένα νέο παιχνίδι (αναγνωριστικό παιχνιδιού)
- Κατάσταση παιχνιδιού = ΥΠΟΒΟΛΗ
- Επιλογή παίκτη (μήκος τμήματος 50)
- Δημόσιο κλειδί
- Πιθανά κέρδη (ανάλογα με το στοίχημα του παίκτη)
Έτσι μοιάζει μια εγγραφή δεδομένων στο blockchain (κλειδί-τιμή):
{
"type": "string",
"value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229",
"key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx"
}
"Κλειδί" (κλειδί) - αναγνωριστικό παιχνιδιού νέο παιχνίδι. Τα υπόλοιπα δεδομένα περιέχονται στη γραμμή του πεδίου "τιμή". Αυτές οι καταχωρήσεις αποθηκεύονται στην καρτέλα ημερομηνία έξυπνο συμβόλαιο:
5. Ο διακομιστής «κοιτάζει» το έξυπνο συμβόλαιο και βρίσκει την απεσταλμένη συναλλαγή (νέο παιχνίδι) χρησιμοποιώντας το blockchain Api. Το αναγνωριστικό παιχνιδιού του νέου παιχνιδιού έχει ήδη καταγραφεί στο blockchain, πράγμα που σημαίνει ότι δεν μπορεί πλέον να αλλάξει ή να επηρεαστεί
6. Ο διακομιστής δημιουργεί μια συνάρτηση απόσυρσης (gameId, rsaSign). Για παράδειγμα, όπως αυτό:
withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")
7. Ο διακομιστής στέλνει μια συναλλαγή Invocation στο smart contract (broadcast InvocationTx). Η συναλλαγή περιέχει μια κλήση προς τη σχηματισμένη συνάρτηση ανάληψης (gameId, rsaSign):
Η συνάρτηση περιέχει αναγνωριστικό παιχνιδιού νέο παιχνίδι και το αποτέλεσμα της υπογραφής RSA ενός μοναδικού αναγνωριστικού με ιδιωτικό κλειδί. Το αποτέλεσμα της υπογραφής παραμένει αμετάβλητο.
Τι σημαίνει αυτό;
Παίρνουμε την ίδια τιμή (αναγνωριστικό παιχνιδιού) και εφαρμόζουμε τη μέθοδο υπογραφής RSA σε αυτήν. Θα έχουμε πάντα το ίδιο αποτέλεσμα. Έτσι λειτουργεί ο αλγόριθμος RSA. Δεν είναι δυνατός ο χειρισμός του τελικού αριθμού, καθώς το αναγνωριστικό του παιχνιδιού και το αποτέλεσμα της εφαρμογής RSA δεν είναι γνωστά. Η επιλογή ενός αριθμού είναι επίσης άσκοπη.
8. Το Blockchain αποδέχεται τη συναλλαγή. Εκτελεί τη λειτουργία απόσυρσης (gameId, rsaSign)
9. Μέσα στη λειτουργία απόσυρσης, πραγματοποιείται απόσυρση GenerateRandInt συναρτήσεις (gameId, rsaSign). Αυτή είναι μια γεννήτρια τυχαίων αριθμών
# @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")
}
όλα - και υπάρχει ένας τυχαίος αριθμός.
Αρχικά, λαμβάνεται η συμβολοσειρά, η οποία είναι το αποτέλεσμα της υπογραφής RSA αναγνωριστικό παιχνιδιού ιδιωτικό κλειδί (rsaSign). Στη συνέχεια κατακερματίστηκε με SHA-256 (sha256(rsaSign)).
Δεν μπορούμε να προβλέψουμε το αποτέλεσμα της υπογραφής και του επακόλουθου κατακερματισμού. Επομένως, είναι αδύνατο να επηρεαστεί η δημιουργία ενός τυχαίου αριθμού. Για να λάβετε έναν αριθμό σε ένα συγκεκριμένο εύρος (για παράδειγμα, από 1 έως 100), χρησιμοποιήστε τη συνάρτηση μετατροπής toInt και %100 (παρόμοια με
Στην αρχή του άρθρου αναφέραμε τη συνάρτηση rsaVerify(), το οποίο σας επιτρέπει να ελέγξετε την εγκυρότητα μιας υπογραφής RSA χρησιμοποιώντας ένα ιδιωτικό κλειδί έναντι ενός δημόσιου. Εδώ είναι το τμήμα GenerateRandInt(gameId,rsaSign):
rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
Το δημόσιο κλειδί RSAPUBLIC και η συμβολοσειρά rsaSign μεταβιβάζονται στην είσοδο. Η υπογραφή ελέγχεται για εγκυρότητα. Ο αριθμός δημιουργείται εάν ο έλεγχος είναι επιτυχής. Διαφορετικά, το σύστημα θεωρεί ότι η υπογραφή δεν είναι έγκυρη (Invalid RSA signature).
Ο διακομιστής πρέπει να υπογράψει το αναγνωριστικό του παιχνιδιού με ένα ιδιωτικό κλειδί και να στείλει μια έγκυρη υπογραφή Rsa εντός 2880 μπλοκ. Η παράμετρος διαμορφώνεται κατά την ανάπτυξη του έξυπνου συμβολαίου. Εάν δεν συμβεί τίποτα εντός του καθορισμένου χρόνου, ο χρήστης κερδίζει. Σε αυτή την περίπτωση, το έπαθλο πρέπει να αποσταλεί μόνος σας στη διεύθυνσή σας. Αποδεικνύεται ότι "δεν είναι κερδοφόρο για τον διακομιστή να εξαπατήσει", επειδή αυτό οδηγεί σε απώλεια. Παρακάτω είναι ένα παράδειγμα.
Ο χρήστης παίζει
Για να δημιουργήσουμε αριθμούς στα παιχνίδια, χρησιμοποιούμε ένα μαντείο - ένα εξωτερικό σύστημα που δεν είναι blockchain. Ο διακομιστής εκτελεί μια υπογραφή RSA του αναγνωριστικού παιχνιδιού. Το έξυπνο συμβόλαιο ελέγχει την εγκυρότητα της υπογραφής και καθορίζει τον νικητή. Εάν ο διακομιστής δεν στείλει τίποτα, τότε ο χρήστης κερδίζει αυτόματα.
Αυτή είναι μια ειλικρινής μέθοδος παραγωγής, γιατί η χειραγώγηση είναι τεχνικά αδύνατη. Όλα τα παιχνίδια Tradisys λειτουργούν με βάση τον περιγραφόμενο αλγόριθμο. Έτσι λειτουργούν τα παιχνίδια blockchain. Όλα είναι διαφανή και επαληθεύσιμα. Δεν υπάρχουν ανάλογα ενός τέτοιου συστήματος σε κανένα άλλο blockchain. Αυτό είναι ένα δίκαιο τυχαίο.
Πηγή: www.habr.com