Problem var - mərkəzləşdirilməmiş şəbəkədə təsadüfi bir nömrə yaratmaq çətindir. Demək olar ki, bütün blokçeynlər bununla artıq qarşılaşıb. Həqiqətən də istifadəçilər arasında etibarın olmadığı şəbəkələrdə danılmaz təsadüfi nömrə yaratmaq bir çox problemi həll edir.
Bu yazıda sizə nümunə olaraq oyunları istifadə edərək problemi necə həll edə bildiyimizi izah edirik. Onlardan birincisi idi
Başlanğıcda biz blokçeyndən gələn məlumat əsasında nömrə yaratmağı planlaşdırdıq. Ancaq sonra aydın oldu: nömrə manipulyasiya edilə bilər, yəni həll uyğun deyil.
Biz bir həll yolu tapdıq: commit-expand sxemindən istifadə edin. Server 1-dən 5-ə qədər bir rəqəm təxmin etdi, ona duz əlavə etdi və sonra nəticəni istifadə edərək hesh etdi
Oyunçu mərc qoydu və server gizli nömrəni və “duz”u ağıllı müqaviləyə göndərdi. Sadə dillə desək, kartları ortaya qoydu. Bundan sonra server nömrələri yoxlayıb və istifadəçinin qalib olub-olmadığına qərar verib.
Server yoxlama üçün nömrə və ya "duz" göndərməsə, istifadəçi qalib gəldi. Bu vəziyyətdə, hər bir oyun üçün əvvəlcədən ağıllı bir müqavilə yerləşdirmək və ona potensial uduşları daxil etmək lazım idi. Əlverişsiz, vaxt aparan və bahalı olduğu ortaya çıxdı. O zaman başqa təhlükəsiz həll yolu yox idi.
Bu yaxınlarda Tradisys komandası Waves protokoluna funksiya əlavə etməyi təklif etdi rsaVerify(). O, açıq və gizli açar əsasında RSA imzasının etibarlılığını yoxlayır. Nəticədə xüsusiyyət əlavə edildi.
Üç oyun hazırladıq:
Nümunə olaraq Ride on Waves istifadə edərək təsadüfi ədəd yaratmağa baxaq. Ağıllı müqavilə tapıla bilər
Nişana keçin Ssenari və seçin Decompilyed. Ağıllı müqavilə kodunu (aka skript) görəcəksiniz.
Ağıllı müqavilə kodu bir sıra funksiyaları ehtiva edir. @Callable kimi qeyd olunanlar istifadə oluna bilər Çağırış əməliyyatları. Bizi iki funksiya maraqlandırır: mərcləşmək и geri:
- func mərc (playerChoice)
- func çıxarılması (oyun kimliyi, rsaSign)
1. İstifadəçi seqmentin uzunluğunu və mərc ölçüsünü seçir.
2. Müştəri mərc funksiyası yaradır. Yuxarıdakı şəkil üçün belə olardı bahis("50").
3. Müştəri ağıllı müqavilə ünvanına (InvocationTx yayımı) bir Çağırış əməliyyatı göndərir. Əməliyyat zəng parametri kimi mərc funksiyasını ehtiva edir. Bu o deməkdir ki, Çağırış əməliyyatı ağıllı müqavilədə mərc funksiyasının (seçim: String) icrasını tetikler.
4. Mərc funksiyasını nəzərdən keçirin:
@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)))
}
}
Funksiya ağıllı müqavilə vəziyyətinə yeni bir oyun yazır. Məhz:
- Yeni oyun üçün unikal identifikator (oyun id)
- Oyun vəziyyəti = TƏQDİM EDİLDİ
- Oyunçunun seçimi (seqment uzunluğu 50)
- Açıq açar
- Potensial uduşlar (oyunçunun mərcindən asılı olaraq)
Blockchain-dəki məlumat qeydi belə görünür (açar-dəyər):
{
"type": "string",
"value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229",
"key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx"
}
"Açar" (açar) - oyun id Yeni oyun. Qalan məlumatlar "dəyər" sahəsinin sətirində yerləşir. Bu girişlər tabda saxlanılır Tarix ağıllı müqavilə:
5. Server smart müqaviləyə “baxır” və blokçeyn Api istifadə edərək göndərilən əməliyyatı (yeni oyunu) tapır. Yeni oyunun Oyun identifikatoru artıq blokçeynində qeydə alınıb, yəni onu artıq dəyişdirmək və ya təsir etmək mümkün deyil.
6. Server geri götürmə funksiyası yaradır (gameId, rsaSign). Məsələn, bu kimi:
withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")
7. Server ağıllı müqaviləyə (InvocationTx yayımı) Çağırış əməliyyatı göndərir. Əməliyyatda formalaşmış geri götürmə funksiyasına (gameId, rsaSign) çağırış daxildir:
Funksiya ehtiva edir oyun id yeni oyun və xüsusi açarla unikal identifikatorun RSA imzalanmasının nəticəsi. İmza nəticəsi dəyişməzdir.
Bu nə deməkdir?
Eyni dəyəri (oyun id) götürürük və ona RSA imza metodunu tətbiq edirik. Həmişə eyni nəticəni alacağıq. RSA alqoritmi belə işləyir. Oyun identifikatoru və RSA-nın tətbiqinin nəticəsi məlum olmadığı üçün son nömrə ilə manipulyasiya etmək mümkün deyil. Nömrə seçmək də mənasızdır.
8. Blockchain əməliyyatı qəbul edir. Çıxarma funksiyasını işə salır (gameId, rsaSign)
9. Çıxarma funksiyasının daxilində geri çəkilmə baş verir GenerateRandInt funksiyaları (oyun kimliyi, rsaSign). Bu təsadüfi ədəd generatorudur
# @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 - və təsadüfi bir nömrə var.
Əvvəlcə RSA imzasının nəticəsi olan sətir götürülür oyun id şəxsi açar (rsaSign). Sonra SHA-256 (sha256(rsaSign)).
İmzanın və sonrakı hashingin nəticəsini təxmin edə bilmərik. Buna görə də təsadüfi ədədin yaranmasına təsir etmək mümkün deyil. Müəyyən diapazonda (məsələn, 1-dən 100-ə qədər) nömrə əldə etmək üçün toInt çevirmə funksiyasından və %100 (oxşar) istifadə edin.
Məqalənin əvvəlində funksiyanı qeyd etdik rsaVerify(), bu, RSA imzasının etibarlılığını açıq açarla yoxlamağa imkan verir. Budur GenerateRandInt(gameId,rsaSign) hissəsi:
rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
RSAPUBLIC açıq açarı və rsaSign sətri girişə ötürülür. İmzanın etibarlılığı yoxlanılır. Çek uğurlu olarsa, nömrə yaradılır. Əks halda, sistem imzanın etibarlı olmadığını hesab edir (Etibarsız RSA imzası).
Server şəxsi açarla oyun id-sini imzalamalı və 2880 blok daxilində etibarlı Rsa imzası göndərməlidir. Parametr ağıllı müqaviləni yerləşdirərkən konfiqurasiya edilir. Ayrılan vaxt ərzində heç nə baş verməzsə, istifadəçi qalib gəlir. Bu halda, mükafat özünüz ünvanınıza göndərilməlidir. Məlum oldu ki, "serverin fırıldaq etməsi sərfəli deyil", çünki bu, itkiyə səbəb olur. Aşağıda bir nümunə verilmişdir.
İstifadəçi oynayır
Oyunlarda nömrələr yaratmaq üçün biz bir oracle - xarici, blokçeyn olmayan sistemdən istifadə edirik. Server oyun id-nin RSA imzasını yerinə yetirir. Ağıllı müqavilə imzanın etibarlılığını yoxlayır və qalibi müəyyən edir. Əgər server heç nə göndərmirsə, o zaman istifadəçi avtomatik olaraq qalib gəlir.
Bu, dürüst nəsil üsuludur, çünki manipulyasiya texniki cəhətdən mümkün deyil. Bütün Tradisys oyunları təsvir olunan alqoritm əsasında işləyir. Blokçeyn oyunları belə işləyir. Hər şey şəffafdır və yoxlanıla bilər. Heç bir başqa blokçeyndə belə bir sistemin analoqu yoxdur. Bu ədalətli təsadüfdür.
Mənbə: www.habr.com