هناك مشكلة - من الصعب إنشاء رقم عشوائي في شبكة لا مركزية. لقد واجهت جميع سلاسل الكتل تقريبًا هذا بالفعل. في الواقع، في الشبكات التي لا توجد فيها ثقة بين المستخدمين، فإن إنشاء رقم عشوائي لا جدال فيه يحل العديد من المشاكل.
نخبرك في هذه المقالة كيف تمكنا من حل المشكلة باستخدام الألعاب كمثال. وكان أولهم
في البداية، خططنا لإنشاء رقم بناءً على معلومات من blockchain. لكن اتضح بعد ذلك: أنه من الممكن التلاعب بالرقم، مما يعني أن الحل غير مناسب.
لقد توصلنا إلى حل بديل: استخدم نظام الالتزام والتوسيع. خمن الخادم رقمًا من 1 إلى 5، وأضاف إليه ملحًا، ثم قام بتجزئة النتيجة باستخدام
وضع اللاعب رهانًا، وأرسل الخادم الرقم المخفي و"الملح" إلى العقد الذكي. بعبارات بسيطة، كشف عن البطاقات. بعد ذلك، يقوم الخادم بفحص الأرقام ويقرر ما إذا كان المستخدم فاز أم خسر.
إذا لم يرسل الخادم رقمًا أو "ملحًا" للتحقق، فاز المستخدم. في هذه الحالة، كان من الضروري لكل لعبة نشر عقد ذكي مسبقًا وإدراج المكاسب المحتملة فيه. اتضح أنها غير مريحة وتستغرق وقتًا طويلاً ومكلفة. في ذلك الوقت لم يكن هناك حل آمن آخر.
مؤخرًا، اقترح فريق Tradisys إضافة وظيفة إلى بروتوكول Waves التحقق من رسا (). يتحقق من صحة توقيع RSA بناءً على المفتاح العام والخاص. ونتيجة لذلك، تمت إضافة الميزة.
لقد قمنا بتطوير ثلاث ألعاب:
دعونا نلقي نظرة على توليد رقم عشوائي باستخدام Ride on Waves كمثال. يمكن العثور على العقد الذكي
انتقل إلى علامة التبويب سيناريو وحدد مفككة. سترى رمز العقد الذكي (المعروف أيضًا باسم البرنامج النصي).
يحتوي رمز العقد الذكي على مجموعة من الوظائف. يمكن إطلاق تلك التي تم وضع علامة عليها كـCallable باستخدام معاملات الاستدعاء. نحن مهتمون بوظيفتين: مراهنة и سحب:
- رهان func (اختيار اللاعب)
- سحب func(gameId,rsaSign)
1. يقوم المستخدم باختيار طول المقطع وحجم الرهان.
2. يقوم العميل بإنشاء وظيفة الرهان. بالنسبة للصورة أعلاه سيكون الرهان("50").
3. يرسل العميل معاملة استدعاء إلى عنوان العقد الذكي (بث InvocationTx). تحتوي المعاملة على وظيفة الرهان كمعلمة اتصال. وهذا يعني أن معاملة الاستدعاء تؤدي إلى تنفيذ وظيفة الرهان (الاختيار: سلسلة) على العقد الذكي.
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. يرسل الخادم معاملة استدعاء إلى العقد الذكي (بث InvocationTx). تحتوي المعاملة على استدعاء لوظيفة السحب المشكلة (gameId، rsaSign):
تحتوي الدالة رقم اللعبة لعبة جديدة ونتيجة توقيع RSA لمعرف فريد بمفتاح خاص. نتيجة التوقيع لم تتغير.
ماذا يعني هذا؟
نأخذ نفس القيمة (معرف اللعبة) ونطبق عليها طريقة توقيع RSA. سنحصل دائما على نفس النتيجة. هذه هي الطريقة التي تعمل بها خوارزمية RSA. لا يمكن التلاعب بالرقم النهائي، حيث أن معرف اللعبة ونتيجة تطبيق RSA غير معروفين. اختيار رقم هو أيضا لا معنى له.
8. تقبل Blockchain المعاملة. يقوم بتشغيل وظيفة السحب (gameId، rsaSign)
9. داخل وظيفة السحب، يحدث السحب وظائف جينيراتراندينت (معرف اللعبة، 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 (مماثلة لـ
في بداية المقال ذكرنا الوظيفة التحقق من رسا ()، والذي يسمح لك بالتحقق من صحة توقيع RSA باستخدام مفتاح خاص مقابل المفتاح العام. إليك الجزء GenerateRandInt(gameId,rsaSign):
rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
يتم تمرير المفتاح العام RSAPUBLIC وسلسلة rsaSign إلى الإدخال. يتم التحقق من صحة التوقيع. يتم إنشاء الرقم في حالة نجاح الشيك. وإلا فإن النظام يعتبر أن التوقيع غير صالح (توقيع RSA غير صالح).
يجب أن يقوم الخادم بتوقيع معرف اللعبة بمفتاح خاص وإرسال توقيع Rsa صالح ضمن 2880 كتلة. يتم تكوين المعلمة عند نشر العقد الذكي. إذا لم يحدث أي شيء خلال الوقت المخصص، يفوز المستخدم. وفي هذه الحالة يجب إرسال الجائزة إلى عنوانك بنفسك. اتضح أنه "ليس من المربح للخادم أن يغش" لأن هذا يؤدي إلى الخسارة. أدناه مثال.
المستخدم يلعب
لتوليد الأرقام في الألعاب، نستخدم أوراكل - وهو نظام خارجي لا يعتمد على تقنية البلوكشين. يقوم الخادم بإجراء توقيع RSA لمعرف اللعبة. يتحقق العقد الذكي من صحة التوقيع ويحدد الفائز. إذا لم يرسل الخادم أي شيء، فسيفوز المستخدم تلقائيًا.
هذه طريقة توليد صادقة، لأن التلاعب مستحيل من الناحية الفنية. تعمل جميع ألعاب Tradisys بناءً على الخوارزمية الموضحة. هذه هي الطريقة التي تعمل بها ألعاب blockchain. كل شيء شفاف ويمكن التحقق منه. لا توجد نظائرها لمثل هذا النظام في أي blockchain آخر. هذا عشوائي عادل.
المصدر: www.habr.com