هذه المقالة عبارة عن ترجمة لمستند تم نشره على صفحة TON blockchain: smc -idelines.txt . ربما هذا سوف يساعد شخص ما على اتخاذ خطوة نحو التطوير لهذه blockchain. أيضا ، في النهاية قدمت ملخصًا قصيرًا.
الرسائل الداخلية
تتفاعل العقود الذكية مع بعضها البعض عن طريق إرسال الرسائل الداخلية المزعومة. عندما تصل الرسالة الداخلية إلى وجهتها المحددة ، يتم إنشاء معاملة منتظمة باسم حساب الوجهة ، وتتم معالجة الرسالة الداخلية وفقًا للرمز المحدد والبيانات الثابتة لهذا الحساب (العقد الذكي). على وجه الخصوص ، قد تنشئ معاملة معالجة واحدة أو أكثر من الرسائل الداخلية ، قد يتم توجيه بعضها إلى عنوان مصدر الرسالة الداخلية قيد المعالجة. يمكن استخدام هذا لإنشاء "تطبيقات خادم عميل" بسيطة عندما يتم تضمين (مغلف) الطلب في رسالة داخلية وإرساله إلى عقد ذكي آخر يعالج الطلب ويرسل الاستجابة مرة أخرى كرسالة داخلية.
يؤدي هذا النهج إلى الحاجة إلى التمييز بين الرسائل الداخلية إلى "الطلب" و "الاستجابة" (ك "استعلام" أو "استجابة") ، أو لا يتطلب أي معالجة إضافية (مثل تحويل أموال بسيط). بالإضافة إلى ذلك ، عند وصول إجابة ، يجب أن تكون هناك طريقة لفهم الطلب الذي يتعلق به.
لتحقيق هذا الهدف ، يوصى باستخدام قالب الرسالة الداخلية التالي (تذكر أن TON blockchain لا تفرض أي قيود على نص الرسالة ، أي أنها مجرد توصية):
0) يمكن تضمين نص الرسالة في الرسالة نفسها ، أو يمكن تخزينها في خلية منفصلة (خلية *) ، المشار إليها في الرسالة ، كما هو مبين في جزء TL-B من الرسم التخطيطي (باللغة الإنجليزية ، من الأسهل فهم: أو تخزينها في ملف منفصل الخلية المشار إليها من الرسالة ، كما هو موضح في جزء مخطط TL-B):
message$_ {X:Type} ... body:(Either X ^X) = Message X;
( https://core.telegram.org/mtproto - هنا يمكنك قراءة مخططات TL)
يجب أن يتقبل العقد الذكي المتلقي الرسائل الداخلية على الأقل مع تضمين نص الرسالة (حتى إذا تم وضعها في الخلية التي تحتوي على الرسالة - كلما تم دمجها في الخلية التي تحتوي على الرسالة - ليس من الواضح تمامًا ما يعنيه هذا ، وبالتالي ، إرفاق النص الأصلي). إذا قبل العقد نصوص الرسائل في خلايا منفصلة (باستخدام المُنشئ "الأيمن" (Either X ^X)
) ، يجب ألا تعتمد معالجة الرسالة الواردة على طريقة معينة لتضمين نص الرسالة. من ناحية أخرى ، من القانوني تمامًا عدم دعم نص الرسالة في خلية منفصلة على الإطلاق لتبسيط الطلبات والردود.
1) عادة ما يبدأ نص الرسالة بالحقول التالية:
- op - 32 بت (big-endian) عدد صحيح غير موقّع يحدد العملية للتنفيذ ، أو طريقة العقد الذكية للاتصال.
- query_id عبارة عن عدد صحيح غير موقّع 64 بت ( end -endian) يُستخدم في كل الأسئلة الداخلية والإجابة على الرسائل لتحديد العلاقة بين الاستجابة للطلب (يجب أن يكون query_id للاستجابة مساوياً query_id للطلب المقابل). إذا لم يكن المرجع عبارة عن طريقة للاستجابة للطلب (تستدعي طريقة لا يتوقع منها استجابة) ، فقد يتم حذف query_id .
- بقية نص الرسالة خاص بكل قيمة معتمدة لمعلمة المرجع
2) إذا كان المرجع هو صفر ، فإن الرسالة عبارة عن رسالة نقل بسيطة مع تعليق. التعليق موجود في الجزء المتبقي من الرسالة (بدون query_id وما إلى ذلك ، أي بدءًا من البايت الخامس (الشرح: إذا لم يكن query_id ، فإن حقل المرجع يأخذ البايتات الأربع الأولى)). إذا لم يبدأ بالبايت 0xff ، فسيكون التعليق نصًا واحدًا ؛)؛ يمكن عرضها على المستخدم النهائي للمحفظة "كما هي" (بعد تصفية الأحرف غير الصالحة والتحكم والتأكد من أنها سلسلة UTF-8 صالحة). على سبيل المثال ، يمكن للمستخدمين تحديد الغرض من النقل البسيط من محفظتهم إلى محفظة مستخدم آخر في هذا الحقل. من ناحية أخرى ، إذا بدأ التعليق بالبايت 0xff ، فإن بقية الرسالة هي "تعليق ثنائي" يجب ألا يتم عرضه للمستخدم النهائي كنص (فقط كملف سداسي عشرية إذا لزم الأمر). الاستخدام المقترح للتعليقات الثنائية ، على سبيل المثال ، هو احتواء معرف الدفع للدفع في المتجر ، ويتم إنشاؤه ومعالجته تلقائيًا بواسطة برنامج المتجر.
لا يتعين على معظم العقود الذكية القيام بأعمال غير تافهة أو رفض رسالة واردة عندما تتلقى "رسالة نقل بسيطة". وبالتالي ، عندما يتحول الأمر op إلى صفر ، فإن وظيفة العقد الذكية لمعالجة الرسائل الداخلية الواردة (تسمى عادةً recv_internal()
) يجب أن تخرج على الفور بالرمز 0 ، مما يشير إلى النجاح (على سبيل المثال ، رمي استثناء 0 إذا لم يتم تثبيت معالج مخصص في العقد الذكي الاستثناءات). سيؤدي ذلك إلى حقيقة أن المبلغ المحول بواسطة الرسالة سيتم إضافته إلى حساب المستلم دون أي تأثير إضافي.
3) "نقل رسالة بسيط بدون تعليقات" له نص فارغ (حتى بدون حقل المرجع ). تنطبق الاعتبارات المذكورة أعلاه على هذه الرسائل. يرجى ملاحظة أن هذه الرسائل يجب أن يكون نصها الأساسي مضمنًا في خلية الرسائل.
4) نتوقع أن يحتوي حقل المرجع لرسائل الطلب على البتة الأولى ("بت عالية الترتيب" ، تُرجم كأول ، قد يكون هذا غير صحيح ، ولكن كما هو موضح لاحقًا يصبح واضحًا) فارغ ، وهذا هو ، يجب أن تكون قيمة الحقل في النطاق 1 .. 2^31-1
، وبالنسبة لرسائل الاستجابة ، يجب أن تكون البتة الأولى (ذات الترتيب العالي) مساوية ل 1 ، أي قيمة الحقل في النطاق 2^31 .. 2^32-1
. إذا كانت الرسالة ليست طلبًا أو استجابة (لا يحتوي النص على المعلمة query_id ) ، فيجب أن تحتوي على المعلمة op في النطاق كما في رسالة الطلب: 1 .. 2^31 - 1
.
5) هناك العديد من رسائل الاستجابة "القياسية" والتي المرجع هو 0xffffffff و 0xffffffffe. بشكل عام ، يتم حجز قيم المرجع من 0xfffffff0 إلى 0xffffffff لهذه الإجابات القياسية.
- op = 0xffffffff يعني "العملية غير مدعومة." يتبعه استعلام 64 بت يتم استخراجه من الاستعلام الأصلي ، ومرجع 32 بت من الاستعلام الأصلي. جميع العقود الذكية باستثناء أبسطها يجب أن تُرجع هذا الخطأ عندما تتلقى طلبًا بمرجع غير معروف في النطاق 1 ... 2 ^ 31-1.
- op = 0xfffffffe يعني "العملية غير مسموح بها." يتبعه استعلام 64 بت من الاستعلام الأصلي ، ثم المرجع 32 بت المستخرج من الاستعلام الأصلي.
لاحظ أنه يجب تجاهل "الإجابات" غير المعروفة (مع المرجع في النطاق 2 ^ 31 ... 2 ^ 32-1) (على وجه الخصوص ، يجب عدم إنشاء استجابة مع المرجع تساوي 0xffffffff) ، وكذلك الإرجاع غير المتوقع ( ارتدت) -الرسائل (مع مجموعة العلم "ارتدت").
دفع لمعالجة الطلبات وإرسال الردود
بشكل عام ، إذا أراد عقد ذكي إرسال طلب إلى عقد ذكي آخر ، فيجب أن يدفع مقابل إرسال رسالة داخلية إلى العقد الذكي المستهدف (رسوم إعادة توجيه الرسائل) ، لمعالجة هذه الرسالة في الوجهة (رسوم الغاز: رسوم الغاز) ولإرسال استجابة إذا لزم الأمر (رسوم إعادة توجيه الرسالة).
في معظم الحالات ، يقوم المرسل بإرفاق كمية صغيرة من الجرام بالرسالة الداخلية (على سبيل المثال ، 1 غرام) (تكفي لدفع مقابل معالجة هذه الرسالة) وتعيين علامة "الارتداد" عليها (أي ، سيتم إرسال رسالة داخلية يمكن ارتداؤها) ؛ سيعود المستلم الجزء غير المستخدم من القيمة المستلمة مع الإجابة (طرح رسوم إرسال الرسالة منه). يتم تحقيق ذلك عادةً عن طريق استدعاء SENDRAWMSG مع الوضع = 64 (راجع الملحق A بمستندات TON VM).
إذا تعذر على المستلم معالجة الرسالة المستلمة وينتهي التنفيذ برمز خروج غير صفري (على سبيل المثال ، بسبب استثناء إلغاء تسلسل الخلية غير المعالج) ، سيتم "رد" الرسالة تلقائيًا إلى المرسل ، وسيتم إلغاء تحديد علامة "الارتداد" وتعيينها. العلم "ارتدت". سيكون نص الرسالة المرتدة هو نفس الرسالة الأصلية ؛ لذلك ، من المهم التحقق من العلامة "المرتجعة" للرسالة الداخلية الواردة قبل تحليل حقل المرجع في العقد الذكي ومعالجة الطلب المقابل (وإلا فهناك مخاطرة في أن تتم معالجة الطلب الوارد في الرسالة المرتدة بواسطة مرسلها الأصلي كطلب منفصل جديد). إذا تم تعيين علامة "ارتداد" ، يمكن لرمز خاص فهم الطلب الذي فشل (على سبيل المثال ، إلغاء تسلسل المرجع و query_id من رسالة مرتدة ) واتخاذ الإجراء المناسب. يمكن لعقد ذكي أبسط ببساطة تجاهل جميع الرسائل التي تم إرجاعها (إنهاء برمز إنهاء صفر إذا تم تعيين علامة "ارتداد").
من ناحية أخرى ، يمكن للمستقبل تحليل الطلب الوارد بنجاح والعثور على أن طريقة المرجع المطلوبة غير مدعومة أو أنه قد تم استيفاء شرط خطأ آخر. ثم يجب إرسال استجابة مع المرجع تساوي 0xffffffff أو قيمة أخرى مناسبة مرة أخرى باستخدام SENDRAWMSG مع الوضع = 64 ، كما ذكر أعلاه.
في بعض الحالات ، يرغب المرسل في تحويل مبلغ معين من المال في نفس الوقت؟ إلى المرسل؟ (هنا ، على ما يبدو ، خطأ ، وكان المقصود به "المستلم") وتلقي إما تأكيد أو رسالة خطأ. على سبيل المثال ، يتلقى العقد الذكي لانتخابات المدقق طلبًا للمشاركة في الانتخابات جنبًا إلى جنب مع محاولة كقيمة مضافة. في مثل هذه الحالات ، يكون من المنطقي أن نعلق ، على سبيل المثال ، غرامًا واحدًا إضافيًا بالقيمة المقدرة [التكلفة] (هنا يتم استخدام قيمة الكلمة في كل مكان ، بمعنى الدفع لبعض الإجراءات ، لذلك استخدمت كلمة "التكلفة"). في حالة حدوث خطأ (على سبيل المثال ، لا يمكن قبول عرض التسعير لأي سبب) ، يجب إعادة المبلغ الكامل المستلم (مطروحًا منه رسوم المعالجة) إلى المرسل مع رسالة الخطأ (على سبيل المثال ، استخدام SENDRAWMSG مع الوضع = 64 ، كما هو موضح أعلاه). إذا نجحت ، يتم إنشاء رسالة تأكيد ويتم إعادة إرسال غرام واحد بالضبط (يتم خصم رسوم نقل الرسالة من هذه القيمة ؛ هذا هو الوضع = 1 من SENDRAWMSG).
باستخدام رسائل غير قابلة للارتداد
يجب إعادة جميع الرسائل الداخلية المرسلة بين العقود الذكية تقريبًا (يمكنك ترجمتها على أنها "ارتداد" ، ولكن حتى لا يتم الخلط ، من الأسهل استخدام هذا المصطلح) ، أي أنه يجب أن يكون "بت" الارتداد غير فارغ. ثم ، إذا لم يكن العقد الذكي المستهدف موجودًا ، أو إذا كان ينشئ استثناءًا غير معالج عند معالجة هذه الرسالة ، فسيتم "إرجاع" الرسالة ، مع تحمل باقي التكلفة (القيمة) الأولية (مطروحًا منها جميع رسوم إرسال الرسائل والغاز). سيكون للرسالة التي تم إرجاعها نفس النص ، ولكن مع إزالة علامة "الارتداد" وتعيين علامة "الارتداد". لذلك ، يجب على جميع العقود الذكية التحقق من العلامة "المرتجعة" لجميع الرسائل الواردة وإما أن تستقبلها بصمت (يتم إنهاؤها على الفور برمز خروج صفر) أو إجراء بعض العمليات الخاصة لتحديد الطلب الذي لم يتم الرد عليه. يجب ألا يتم تنفيذ الطلب الموجود في نص الرسالة التي تم إرجاعها.
في بعض الحالات ، يجب استخدام الرسائل الداخلية غير القابلة للارتداد. على سبيل المثال ، لا يمكن إنشاء حساب جديد بدون إرسال رسالة داخلية واحدة على الأقل غير قابلة للإلغاء. إذا كانت هذه الرسالة لا تحتوي على StateInit مع رمز وبيانات العقد الذكي الجديد ، فلا معنى لوجود نص غير فارغ في رسالة داخلية لا تُرجع.
إنها لفكرة جيدة ألا تسمح للمستخدم النهائي (على سبيل المثال ، المحفظة) بإرسال رسائل لا رجعة فيها تحمل كمية كبيرة (على سبيل المثال ، أكثر من خمسة غرامات) ، أو على الأقل تحذيرهم إذا حاولوا القيام بذلك. من الأفضل إرسال مبلغ صغير أولاً ، ثم إنشاء عقد ذكي جديد ، ثم إرسال مبلغ أكبر.
الرسائل الخارجية
يتم إرسال الرسائل الخارجية إلى الخارج إلى العقود الذكية الموجودة في TON blockchain لإجبارهم على تنفيذ إجراءات معينة. على سبيل المثال ، يتوقع العقد الذكي للمحفظة تلقي رسائل خارجية تحتوي على أوامر (على سبيل المثال ، الرسائل الداخلية التي سيتم إرسالها من العقد الذكي للمحفظة) الموقعة من صاحب المحفظة ؛ عندما يتم تلقي هذه الرسالة الخارجية من خلال عقد المحفظة الذكي ، فإنها تتحقق أولاً من التوقيع ، ثم تستقبل الرسالة (عن طريق إطلاق TVM ACCEPT البدائي) ، ثم تقوم بتنفيذ جميع الإجراءات اللازمة.
يرجى ملاحظة أنه يجب حماية جميع الرسائل الخارجية من هجمات الإعادة. يقوم المدققون عادةً بإزالة رسالة خارجية من مجموعة الرسائل الخارجية المقترحة (المتلقاة من الشبكة) ؛ ومع ذلك ، في بعض الحالات ، قد يقوم مدقق آخر بمعالجة الرسالة الخارجية نفسها مرتين (وبالتالي إنشاء معاملة ثانية لنفس الرسالة الخارجية ، مما يؤدي إلى تكرار الإجراء الأصلي). والأسوأ من ذلك ، يمكن للمهاجم استخراج رسالة خارجية من كتلة تحتوي على معاملة معالجة وإعادة إرسالها لاحقًا. هذا يمكن أن يسبب ، على سبيل المثال ، عقد محفظة ذكية لتكرار الدفع.
أسهل طريقة لحماية العقود الذكية من استنشاق الهجمات المرتبطة بالرسائل الخارجية هي تخزين العداد cur-seqno 32 بت في البيانات الثابتة للعقد الذكي والانتظار لقيمة req-seqno في (الجزء الموقع) من أي رسائل خارجية واردة. ثم يتم قبول الرسالة الخارجية (ACCEPTed - تلميح من ACCEPT البدائي) فقط إذا كان التوقيع صالحًا و req-seqno تساوي cur-seqno . بعد المعالجة الناجحة ، تزيد قيمة cur-seqno في البيانات المستمرة بواحد ، وبالتالي لن يتم استلام الرسالة الخارجية نفسها مرة أخرى.
يمكنك أيضًا تضمين حقل انتهاء الصلاحية في رسالة خارجية وقبول الرسالة فقط إذا كان وقت يونكس الحالي أقل من قيمة هذا الحقل. هذا النهج يمكن استخدامها في تركيبة مع seqno . بدلاً من ذلك ، يمكن للعقد الذكي المتلقي تخزين مجموعة (تجزئة) لجميع الرسائل الخارجية المستلمة (غير منتهية الصلاحية) في بياناتها الدائمة ورفض رسالة خارجية جديدة إذا كانت نسخة مكررة من إحدى الرسائل المحفوظة. يجب عليك أيضًا تطبيق جمع وإزالة الرسائل منتهية الصلاحية في هذه المجموعة لتجنب نمو غير محدود للبيانات المستمرة.
كقاعدة عامة ، تبدأ رسالة خارجية بتوقيع 256 بت (إذا لزم الأمر) ، و req-seqno 32 بت (إذا لزم الأمر) ، وتنتهي صلاحية 32 بت (إذا لزم الأمر) ، وربما المرجع 32 بت وغيرها من المعلمات الضرورية في اعتمادا على المرجع . ليس من الضروري أن يكون قالب الرسالة الخارجية موحدًا مثل قالب الرسائل الداخلية ، نظرًا لعدم استخدام الرسائل الخارجية للتفاعل بين العقود الذكية المختلفة (يكتبها مطورون مختلفون ويديرها مالكون مختلفون).
الحصول على الأساليب
من المتوقع أن تنفذ بعض العقود الذكية بعض أساليب الحصول على معرفة جيدة. على سبيل المثال ، من المتوقع أن يقوم أي عقد ذكي لمحلل نظام أسماء النطاقات لـ TON DNS بتطبيق طريقة الحصول على dnsresolve. يمكن للعقود الذكية المخصصة تحديد أساليب الحصول المحددة. توصيتنا العامة الوحيدة في الوقت الحالي هي تنفيذ طريقة الحصول على "seqno" (بدون معلمات) ، والتي تقوم بإرجاع seqno الحالي للعقد الذكي ، والذي يستخدم أرقام تسلسلية لمنع هجمات التشغيل المرتبطة بالوسائل الخارجية الواردة كلما معنى.
القاموس:
- تتكون الخلية - TVM من أكثر من 1023 بت من البيانات ، وعلى الأكثر أربعة إشارات إلى خلايا أخرى. يتم تمثيل جميع البيانات المستمرة (بما في ذلك رمز TVM) في TON Blockchain كمجموعة من خلايا TVM (راجع [1 ، 2.5.14]). - لا تتكون خلية TVM من أكثر من 1023 بت من البيانات ولا تزيد عن أربعة ارتباطات بخلايا أخرى. يتم تقديم جميع البيانات المستمرة (بما في ذلك رمز TVM) في TON blockchain كمجموعة من خلايا TVM (راجع [1 ، 2.5.14]). - مقتطف من وصف TON Virtual Machine ( https://test.ton.org/tvm.pdf )
ما هي الاستنتاجات التي يمكن استخلاصها بناءً على ما قرأته؟
- يمكنك إرسال رسائل خارجية إلى العقود لتحريك إجراء ما.
- الهجمات - هناك ، على سبيل المثال ، هجمات الإعادة
- يجدر بنا جعل طريقة seqno للحماية من هجمات الإعادة.
- تحل محللات نظام أسماء النطاقات طريقة dnsresolve
- يمكنك تخزين علامات التجزئة للرسائل الخارجية للحماية من الهجمات ، ولكن يجب عليك حذفها في الوقت المناسب ، لذلك يجدر استخدام حقل منتهي الصلاحية للرسائل الخارجية
- الرسائل غير المرتجعة مطلوبة فقط لإنشاء العقود ؛ وإلا ، فإن جميع الرسائل الداخلية يتم إرجاعها
- يجب أن تحتوي رسائل استجابة الطلب على الحقول التالية: المرجع ، query_id - اختياري ، والبعض الآخر يعتمد على قيمة المرجع
- يمكنك إرفاق تعليقات نصية بتنسيق UTF-8 للأشخاص و "تعليقات ثنائية" للقراءة التلقائية ومعالجتها بواسطة برنامج تابع لجهة خارجية.
- الأمر يستحق التعامل مع الاستثناءات والقيام بذلك بحكمة
- "رسالة بسيطة بدون تعليقات" - يجب أن يكون لها نص فارغ
- تأخذ بت عالية ترتيب رسائل استجابة الطلب قيمة 0 لرسائل الطلب ، وقيمة 1 لرسائل الاستجابة
- هناك قيم المرجع القياسية لرسائل الاستجابة لتحديد الأخطاء
- إذا تم تلقي رسالة استجابة مع المرجع المجهول ، فيجب تجاهلها ، أي التنفيذ الكامل بالرمز 0
- يجب أن تدفع ثمن إرسال الرسائل ، والغاز وإرسال الرد. في الوقت نفسه ، إذا أرسل أكثر من اللازم ، فستعود الزيادة في الإجابة.
- عند تلقي الرسائل ، يجدر دائمًا التحقق من العلم المرتد أولاً.
شكرا لاهتمامكم ، سأكون سعيدا لردود الفعل البناءة!