أخبارالمطورينإدخالالمشروع Blockchain شرح الأحداث والمؤتمرات الصحافةالنشرات الإخبارية
اشترك في نشرتنا الإخبارية.
عنوان بريد الكتروني
نحن نحترم خصوصيتك
الرئيسيةالمدونةتطوير Blockchain
أفضل ممارسات Solidity لأمان العقود الذكية
من المراقبة إلى اعتبارات الطابع الزمني ، إليك بعض النصائح الاحترافية لضمان تعزيز عقود Ethereum الذكية. by ConsenSys 21 أغسطس 2020 نُشرت في 21 أغسطس 2020
بواسطة ConsenSys Diligence ، فريقنا المكون من خبراء أمان blockchain.
إذا كنت قد أخذت عقلية أمان العقود الذكية على محمل الجد وتتعامل مع خصوصيات EVM ، فقد حان الوقت للنظر في بعض أنماط الأمان الخاصة بلغة برمجة Solidity. في هذه الجولة ، سنركز على توصيات التطوير الآمنة لـ Solidity والتي قد تكون مفيدة أيضًا لتطوير العقود الذكية بلغات أخرى.
حسنًا ، دعنا ننتقل.
استخدم تأكيد () ، يتطلب () ، تراجع () بشكل صحيح
وظائف الراحة يجزم و تطلب يمكن استخدامها للتحقق من الشروط وطرح استثناء إذا لم يتم استيفاء الشرط.
ال يجزم يجب استخدام الوظيفة فقط لاختبار الأخطاء الداخلية ، وللتحقق من الثوابت.
ال تطلب يجب استخدام الوظيفة لضمان الشروط الصالحة ، مثل المدخلات ، أو استيفاء متغيرات حالة العقد ، أو للتحقق من صحة قيم الإرجاع من الاستدعاءات إلى العقود الخارجية.
يتيح اتباع هذا النموذج لأدوات التحليل الرسمية التحقق من عدم إمكانية الوصول إلى كود التشغيل غير الصحيح: مما يعني عدم انتهاك أي ثوابت في الكود وأنه تم التحقق من الرمز رسميًا.
صلابة براغما ^ 0.5.0 ؛ مشارك العقد {وظيفة sendHalf (عنوان الدفع العنوان) المرتجعات العامة المستحقة الدفع (رصيد uint) {تتطلب (msg.value٪ 2 == 0, "حتى القيمة المطلوبة.") ؛ // Require () يمكن أن يكون له سلسلة رسالة اختيارية uint BalanceBeforeTransfer = address (this) .balance؛ (نجاح منطقي ،) = addr.call.value (msg.value / 2) ("") ؛ تتطلب (النجاح) ؛ // نظرًا لأننا عدنا إذا فشلت عملية النقل ، فلا ينبغي أن يكون هناك // أي طريقة لنا حتى لا يزال لدينا نصف الأموال. تأكيد (العنوان (هذا) .balance == BalanceBeforeTransfer – msg.value / 2) ؛ // المستخدمة للتحقق من الخطأ الداخلي عنوان المرسل (this) .balance ؛ }} لغة الشفرة: JavaScript (javascript)
استخدم المعدلات فقط للشيكات
عادةً ما يتم تنفيذ الكود الموجود داخل المُعدِّل قبل جسم الوظيفة ، لذا فإن أي تغييرات في الحالة أو المكالمات الخارجية سوف تنتهك الشيكات والتأثيرات والتفاعلات نمط. علاوة على ذلك ، قد تظل هذه العبارات أيضًا دون أن يلاحظها أحد من قبل المطور ، لأن كود المعدل قد يكون بعيدًا عن إعلان الوظيفة. على سبيل المثال ، يمكن أن يؤدي استدعاء خارجي في المعدل إلى هجوم إعادة الدخول:
سجل العقد {مالك العنوان؛ function isVoter (address _addr) external return (bool) {// Code}} contraction {Registry Registry؛ المُعدِّل مؤهل (العنوان _addr) {يتطلب (register.isVoter (_addr)) ؛ _ ؛ } وظيفة التصويت () مؤهلة (msg.sender) عامة {// Code}} لغة الشفرة: جافا سكريبت (جافا سكريبت)
في هذه الحالة ، يمكن لعقد السجل إجراء هجوم إعادة قرصنة عن طريق استدعاء Election.vote () داخل isVoter ().
ملحوظة: يستخدم الصفات التعريفية لاستبدال فحوصات الشرط المكررة في وظائف متعددة ، مثل isOwner () ، وإلا استخدم طلب أو التراجع داخل الوظيفة. هذا يجعل رمز العقد الذكي الخاص بك أكثر قابلية للقراءة وأسهل للتدقيق.
احذر التقريب مع القسمة الصحيحة
يتم تقريب كل قسمة عدد صحيح لأسفل إلى أقرب عدد صحيح. إذا كنت بحاجة إلى مزيد من الدقة ، ففكر في استخدام مُضاعِف ، أو خزن كلًا من البسط والمقام.
(في المستقبل ، سيكون لدى Solidity ملف نقطة ثابتة اكتب ، مما سيجعل هذا أسهل.)
// سيئة uint x = 5/2 ؛ // النتيجة هي 2 ، جميع أقسام الأعداد الصحيحة تقرب لأسفل إلى أقرب عدد صحيح لغة الرمز: جافا سكريبت (جافا سكريبت)
استخدام المضاعف يمنع التقريب ، يجب حساب هذا المضاعف عند العمل مع x في المستقبل:
// مضاعف uint جيد = 10 ؛ uint x = (5 * مضاعف) / 2 ؛ لغة الشفرة: JavaScript (جافا سكريبت)
يعني تخزين البسط والمقام أنه يمكنك حساب نتيجة البسط / المقام خارج السلسلة:
// good uint بسط = 5 ؛ مقام uint = 2 ؛ لغة الكود: جافا سكريبت (جافا سكريبت)
كن على علم بالمفاضلات بين عقود مجردة و واجهات
توفر كل من الواجهات والعقود المجردة واحدة بنهج قابل للتخصيص وإعادة الاستخدام للعقود الذكية. تشبه الواجهات ، التي تم تقديمها في Solidity 0.4.11 ، العقود المجردة ولكن لا يمكن تنفيذ أي وظائف بها. تحتوي الواجهات أيضًا على قيود مثل عدم القدرة على الوصول إلى التخزين أو التوريث من واجهات أخرى مما يجعل العقود المجردة أكثر عملية بشكل عام. على الرغم من أن الواجهات مفيدة بالتأكيد في تصميم العقود قبل التنفيذ. بالإضافة إلى ذلك ، من المهم أن تضع في اعتبارك أنه إذا كان العقد يرث من عقد مجرد ، فيجب أن ينفذ جميع الوظائف غير المنفذة من خلال التجاوز أو سيكون مجردًا أيضًا..
وظائف احتياطية
اجعل الوظائف الاحتياطية بسيطة
وظائف احتياطية يتم استدعاؤها عندما يتم إرسال رسالة بعقد بدون وسيطات (أو عندما لا تتطابق وظيفة) ، ويكون لها حق الوصول إلى 2300 غاز فقط عند استدعائها من .send () أو .transfer (). إذا كنت ترغب في أن تكون قادرًا على تلقي إيثر من .send () أو .transfer () ، فإن أقصى ما يمكنك فعله في وظيفة احتياطية هو تسجيل حدث. استخدم وظيفة مناسبة إذا كان حساب المزيد من الغاز مطلوبًا.
// دالة سيئة () مستحقة الدفع {أرصدة [msg.sender] + = msg.value؛ } // إيداع دالة جيدة () مستحق الدفع خارجي {أرصدة [msg.sender] + = msg.value؛ } function () payable {due (msg.data.length == 0)؛ ينبعث LogDepositReceived (msg.sender) ؛ } لغة الكود: JavaScript (javascript)
تحقق من طول البيانات في الوظائف الاحتياطية
منذ وظائف احتياطية لا يُستدعى فقط لعمليات نقل الإيثر العادي (بدون بيانات) ولكن أيضًا في حالة عدم تطابق أي وظيفة أخرى ، يجب عليك التحقق من أن البيانات فارغة إذا كان الغرض من الوظيفة الاحتياطية هو استخدامها فقط لغرض تسجيل إيثر المستلم. خلاف ذلك ، لن يلاحظ المتصلون ما إذا تم استخدام عقدك بشكل غير صحيح ويتم استدعاء الوظائف غير الموجودة.
// دالة سيئة () مستحقة الدفع {emit LogDepositReceived (msg.sender) ؛ } // good function () payable {due (msg.data.length == 0)؛ ينبعث LogDepositReceived (msg.sender) ؛ } لغة الكود: JavaScript (javascript)
وضع علامة صراحة على الوظائف المستحقة الدفع ومتغيرات الحالة
بدءًا من Solidity 0.4.0 ، يجب أن تستخدم كل وظيفة تتلقى الأثير معدل الدفع ، وإلا إذا كانت المعاملة تحتوي على قيمة msg.value > 0 سيعود (إلا عندما يجبر).
ملحوظة: شيء قد لا يكون واضحًا: ينطبق معدِّل الدفع فقط على المكالمات الواردة من العقود الخارجية. إذا قمت باستدعاء وظيفة غير مستحقة الدفع في الوظيفة المستحقة الدفع في نفس العقد ، فلن تفشل الوظيفة غير المستحقة الدفع ، على الرغم من أن قيمة msg.value لا تزال محددة.
حدد بوضوح الرؤية في الوظائف ومتغيرات الحالة
حدد بوضوح رؤية الوظائف ومتغيرات الحالة. يمكن تحديد الوظائف على أنها خارجية أو عامة أو داخلية أو خاصة. يرجى فهم الاختلافات بينهما ، على سبيل المثال ، الخارجية قد تكون كافية بدلاً من العامة. بالنسبة لمتغيرات الحالة الخارجية غير ممكن. إن تسمية الرؤية بشكل صريح ستجعل من السهل اكتشاف الافتراضات غير الصحيحة حول من يمكنه استدعاء الوظيفة أو الوصول إلى المتغير.
- الوظائف الخارجية هي جزء من واجهة العقد. لا يمكن استدعاء دالة خارجية f داخليًا (بمعنى أن f () لا تعمل ، ولكن this.f () تعمل). تكون الوظائف الخارجية في بعض الأحيان أكثر كفاءة عندما تتلقى مصفوفات كبيرة من البيانات.
- تعد الوظائف العامة جزءًا من واجهة العقد ويمكن استدعاؤها داخليًا أو عبر الرسائل. بالنسبة لمتغيرات الحالة العامة ، يتم إنشاء وظيفة getter تلقائية (انظر أدناه).
- لا يمكن الوصول إلى الوظائف الداخلية ومتغيرات الحالة إلا داخليًا ، دون استخدام هذا.
- تكون الوظائف الخاصة ومتغيرات الحالة مرئية فقط للعقد الذي تم تحديده فيه وليس في العقود المشتقة. ملحوظة: كل ما هو داخل عقد مرئي لجميع المراقبين خارج blockchain ، حتى المتغيرات الخاصة.
// bad uint x ؛ // الافتراضي هو داخلي لمتغيرات الحالة ، ولكن يجب جعلها دالة صريحة buy () {// الافتراضي هو public // public code} // good uint private y؛ function buy () external {// only callable externally or using this.buy ()} function Utility () public {// callable خارجيًا ، وكذلك داخليًا: يتطلب تغيير هذا الرمز التفكير في كلتا الحالتين. } function internalAction () internal {// internal code} Code language: PHP (php)
قفل التطبيق العملي لإصدار مترجم معين
يجب نشر العقود باستخدام نفس إصدار المترجم والعلامات التي تم اختبارها بها أكثر من غيرها. يساعد قفل pragma على ضمان عدم نشر العقود عن طريق الخطأ باستخدام ، على سبيل المثال ، أحدث مترجم قد يكون لديه مخاطر أعلى من الأخطاء غير المكتشفة. يمكن أيضًا نشر العقود من قبل الآخرين ويشير pragma إلى إصدار المترجم الذي يقصده المؤلفون الأصليون.
// صلابة براغما السيئة ^ 0.4.4 ؛ // good pragma Solidity 0.4.4 ؛ لغة الكود: جافا سكريبت (جافا سكريبت)
ملحوظة: نسخة براغما العائمة (على سبيل المثال. ^ 0.4.25) ستجمع بشكل جيد مع 0.4.26-nightly.2018.9.25 ، ولكن لا ينبغي أبدًا استخدام الإصدارات الليلية لتجميع التعليمات البرمجية للإنتاج.
تحذير: يمكن السماح لبيانات براغما بالتعويم عندما يكون العقد مخصصًا للاستهلاك من قبل مطورين آخرين ، كما في حالة العقود في مكتبة أو حزمة EthPM. خلاف ذلك ، سيحتاج المطور إلى تحديث pragma يدويًا من أجل التحويل البرمجي محليًا.
نرى SWC-103
استخدم الأحداث لمراقبة نشاط العقد
قد يكون من المفيد أن يكون لديك طريقة لمراقبة نشاط العقد بعد نشره. تتمثل إحدى طرق تحقيق ذلك في النظر إلى جميع معاملات العقد ، ولكن قد يكون ذلك غير كافٍ ، حيث لا يتم تسجيل مكالمات الرسائل بين العقود في blockchain. علاوة على ذلك ، فإنه يعرض معلمات الإدخال فقط ، وليس التغييرات الفعلية التي يتم إجراؤها على الحالة. كما يمكن استخدام الأحداث لتشغيل وظائف في واجهة المستخدم.
مؤسسة خيرية تعاقدية {تعيين (عنوان => uint) أرصدة ؛ function donate () payable public {balances [msg.sender] + = msg.value؛ }} Contract Game {function buyCoins () payable public {// 5٪ يذهب إلى charity charity.donate.value (msg.value / 20) ()؛ }} لغة الشفرة: JavaScript (javascript)
هنا ، سيقوم عقد اللعبة بإجراء مكالمة داخلية إلى Charity.donate (). لن تظهر هذه المعاملة في قائمة المعاملات الخارجية للمؤسسة الخيرية ، ولكنها تظهر فقط في المعاملات الداخلية.
الحدث هو وسيلة مناسبة لتسجيل شيء حدث في العقد. تظل الأحداث التي تم إصدارها في blockchain جنبًا إلى جنب مع بيانات العقد الأخرى وهي متاحة للتدقيق في المستقبل. فيما يلي تحسين للمثال أعلاه ، باستخدام الأحداث لتقديم سجل لتبرعات المؤسسة الخيرية.
عقد خيرية {// تحديد حدث الحدث LogDonate (uint _amount) ؛ تعيين (العنوان => uint) أرصدة ؛ function donate () payable public {balances [msg.sender] + = msg.value؛ // ينبعث الحدث من LogDonate (msg.value) ؛ }} Contract Game {function buyCoins () payable public {// 5٪ يذهب إلى charity charity.donate.value (msg.value / 20) ()؛ }} لغة الشفرة: JavaScript (javascript)
هنا ، ستظهر جميع المعاملات التي تتم من خلال عقد العمل الخيري ، سواء بشكل مباشر أم لا ، في قائمة الأحداث الخاصة بهذا العقد إلى جانب مبلغ الأموال المتبرع بها.
ملاحظة: تفضل بنيات Solidity الأحدث. يفضل التركيبات / الأسماء المستعارة مثل التدمير الذاتي (على الانتحار) و keccak256 (على sha3). يمكن أيضًا تبسيط أنماط مثل تتطلب (msg.sender.send (1 ether)) لاستخدام النقل () ، كما هو الحال في msg.sender.transfer (1 إيثر). الدفع سجل التغيير Solidity لمزيد من التغييرات المماثلة.
اعلم أنه يمكن التظليل “العناصر المضمنة”
من الممكن حاليا أن ظل الكرات الأرضية المدمجة في Solidity. يسمح هذا للعقود بتجاوز وظائف العناصر المضمنة مثل msg و revert (). عل الرغم من هذا والمقصود, يمكن أن يضلل مستخدمي العقد فيما يتعلق بالسلوك الحقيقي للعقد.
عقد PretendingToRevert {function revert () ثابت داخلي {}} عقد ExampleContract is PretendingToRevert {function somethingBad () public {revert ()؛ }}
يجب أن يكون مستخدمو العقود (والمدققون) على دراية بكود مصدر العقد الذكي الكامل لأي تطبيق يعتزمون استخدامه.
تجنب استخدام ملف tx.origin
لا تستخدم مطلقًا tx.origin للحصول على تفويض ، فقد يكون لعقد آخر طريقة تستدعي عقدك (حيث يكون لدى المستخدم بعض الأموال على سبيل المثال) وسيفوض العقد هذه المعاملة لأن عنوانك موجود في tx.origin.
عقد MyContract {عنوان مالك؛ الوظيفة MyContract () public {owner = msg.sender؛ } وظيفة sendTo (عنوان المتلقي ، كمية uint) عامة {تتطلب (tx.origin == مالك) ؛ (نجاح منطقي ،) = receiver.call.value (المبلغ) ("") ؛ تتطلب (النجاح) ؛ }} contract AttackingContract {MyContract myContract؛ عنوان المهاجم function AttackingContract (address myContractAddress) public {myContract = MyContract (myContractAddress)؛ المهاجم = msg.sender ؛ } function () public {myContract.sendTo (attacker، msg.sender.balance)؛ }} لغة الشفرة: JavaScript (javascript)
يجب عليك استخدام msg.sender للحصول على إذن (إذا كان هناك عقد آخر يتصل بك ، فسيكون مرسل الرسالة هو عنوان العقد وليس عنوان المستخدم الذي دعا العقد).
يمكنك قراءة المزيد عنه هنا: مستندات Solidity
تحذير: إلى جانب مشكلة التفويض ، هناك احتمال أن تتم إزالة tx.origin من بروتوكول Ethereum في المستقبل ، لذلك لن يكون الرمز الذي يستخدم tx.origin متوافقًا مع الإصدارات المستقبلية فيتاليك: “لا تفترض أن tx.origin سيظل صالحًا للاستخدام أو مفيدًا.”
من الجدير بالذكر أيضًا أنه باستخدام tx.origin ، فإنك تحد من إمكانية التشغيل البيني بين العقود لأن العقد الذي يستخدم tx.origin لا يمكن استخدامه بواسطة عقد آخر حيث لا يمكن أن يكون العقد tx.origin.
نرى SWC-115
اعتماد الطابع الزمني
هناك ثلاثة اعتبارات رئيسية عند استخدام الطابع الزمني لتنفيذ وظيفة مهمة في العقد ، لا سيما عندما تتضمن الإجراءات تحويل الأموال.
التلاعب بالطابع الزمني
اعلم أن الطابع الزمني للكتلة يمكن أن يتلاعب به عامل منجم. ضع في اعتبارك هذا اتفافية:
ملح خاص ثابت uint256 = block.timestamp؛ دالة عشوائية (uint Max) عوائد خاصة ثابتة (نتيجة uint256) {// الحصول على أفضل بذور للعشوائية uint256 x = salt * 100 / Max؛ uint256 y = salt * block.number / (ملح٪ 5) ؛ uint256 بذرة = block.number / 3 + (ملح٪ 300) + Last_Payout + y ؛ uint256 h = uint256 (block.blockhash (البذور)) ؛ عودة uint256 ((ح / س))٪ ماكس + 1 ؛ // رقم عشوائي بين 1 و Max} لغة الشفرة: PHP (php)
عندما يستخدم العقد الطابع الزمني لبذر رقم عشوائي ، يمكن للمُعدِّن في الواقع نشر طابع زمني في غضون 15 ثانية من التحقق من صحة الكتلة ، مما يسمح بشكل فعال للمُعدِّن بإجراء حساب مسبق لخيار أكثر ملاءمة لفرصه في اليانصيب. الطوابع الزمنية ليست عشوائية ولا يجب استخدامها في هذا السياق.
قاعدة الـ 15 ثانية
ال ورق أصفر (المواصفات المرجعية لـ Ethereum) لا تحدد قيدًا على مقدار الكتل التي يمكن أن تنجرف في الوقت المناسب ، ولكن لا تحدد أن كل طابع زمني يجب أن يكون أكبر من الطابع الزمني الخاص به. تطبيقات بروتوكول Ethereum الشعبية جيث و التكافؤ كلاهما يرفض الكتل ذات الطابع الزمني لأكثر من 15 ثانية في المستقبل. لذلك ، فإن القاعدة الأساسية الجيدة في تقييم استخدام الطابع الزمني هي: إذا كان مقياس الحدث المعتمد على الوقت الخاص بك يمكن أن يختلف بمقدار 15 ثانية مع الحفاظ على النزاهة ، فمن الآمن استخدام كتلة..
تجنب استخدام block.number كطابع زمني
من الممكن تقدير دلتا الوقت باستخدام خاصية block.number و متوسط وقت الكتلة, لكن هذا ليس دليلًا مستقبليًا حيث قد تتغير أوقات الحظر (مثل إعادة تنظيم الشوكة و ال قنبلة صعوبة). في البيع الذي يمتد لأيام ، تسمح قاعدة الـ 15 ثانية للشخص بتحقيق تقدير أكثر موثوقية للوقت.
نرى SWC-116
تعدد حذر الميراث
عند استخدام الوراثة المتعددة في Solidity ، من المهم أن نفهم كيف يؤلف المترجم الرسم البياني للوراثة.
عقد نهائي {غير عام أ؛ الوظيفة النهائية (uint f) public {a = f؛ }} العقد B نهائي {int public fee؛ الوظيفة B (uint f) Final (f) public {} function setFee () public {fee = 3؛ }} العقد C هو {int public fee؛ الوظيفة C (uint f) Final (f) public {} function setFee () public {fee = 5؛ }} العقد A هو B، C {function A () public B (3) C (5) {setFee ()؛ }} لغة الكود: PHP (php)
عندما يتم نشر العقد ، سيقوم المترجم بترتيب الميراث من اليمين إلى اليسار (بعد الكلمة الأساسية يتم سرد الوالدين من الأكثر تشابهًا إلى الأكثر اشتقاقًا). هنا خطي العقد أ:
أخير <- ب <- ج <- أ
ستنتج نتيجة الخطية قيمة رسوم قدرها 5 ، لأن C هو العقد الأكثر اشتقاقًا. قد يبدو هذا واضحًا ، لكن تخيل سيناريوهات يكون فيها C قادرًا على تظليل الوظائف الحاسمة ، وإعادة ترتيب الجمل المنطقية ، والتسبب في قيام المطور بكتابة عقود قابلة للاستغلال. لا يثير التحليل الساكن حاليًا مشكلة تتعلق بالوظائف المظللة ، لذلك يجب فحصها يدويًا.
للمساعدة في المساهمة ، تمتلك شركة Solidity’s Github المشروع مع جميع القضايا المتعلقة بالميراث.
نرى SWC-125
استخدم نوع الواجهة بدلاً من العنوان لكتابة الأمان
عندما تأخذ الوظيفة عنوان العقد كوسيطة ، فمن الأفضل تمرير واجهة أو نوع العقد بدلاً من العنوان الأولي. إذا تم استدعاء الوظيفة في مكان آخر داخل الكود المصدري ، فسيقوم المترجم بتوفير ضمانات أمان إضافية للنوع.
هنا نرى بديلين:
مدقق العقد {وظيفة التحقق من صحة (uint) العوائد الخارجية (منطقي) ؛ } عقد TypeSafeAuction {// good function validateBet (Validator _validator، uint _value) عوائد داخلية (bool) {bool valid = _validator.validate (_value)؛ عودة صالحة }} Contract TypeUnsafeAuction {// bad function validateBet (address _addr، uint _value) عوائد داخلية (bool) {Validator validator = Validator (_addr)؛ منطقي صحيح = validator.validate (_value) ؛ عودة صالحة }} لغة الشفرة: JavaScript (javascript)
يمكن بعد ذلك رؤية فوائد استخدام عقد TypeSafeAuction أعلاه من المثال التالي. إذا تم استدعاء ValidateBet () باستخدام وسيطة عنوان ، أو نوع عقد آخر غير Validator ، فسيرمي المترجم هذا الخطأ:
عقد NonValidator {} المزاد هو TypeSafeAuction {NonValidator nonValidator؛ دالة bet (uint _value) {bool valid = validateBet (nonValidator، _value) ؛ // TypeError: نوع غير صالح للوسيطة في استدعاء الوظيفة. // تحويل ضمني غير صالح من عقد NonValidator // إلى مدقق عقد مطلوب. }} لغة الشفرة: JavaScript (javascript)
تجنب استخدام extcodesize للتحقق من الحسابات المملوكة خارجيًا
غالبًا ما يتم استخدام المُعدِّل التالي (أو فحص مشابه) للتحقق مما إذا كان قد تم إجراء مكالمة من حساب مملوك خارجيًا (EOA) أو حساب عقد:
// معدّل سيئ isNotContract (العنوان _a) {uint size؛ التجميع {الحجم: = extcodesize (_a)} يتطلب (الحجم == 0) ؛ _ ؛ } لغة الكود: JavaScript (javascript)
الفكرة مباشرة: إذا كان العنوان يحتوي على رمز ، فهو ليس EOA ولكنه حساب عقد. ومع ذلك, العقد لا يحتوي على كود مصدر متاح أثناء البناء. هذا يعني أنه أثناء تشغيل المُنشئ ، يمكنه إجراء مكالمات لعقود أخرى ، لكن توسيع الشفرة لعنوانه يعطي صفرًا. يوجد أدناه مثال بسيط يوضح كيف يمكن التحايل على هذا الشيك:
عقد OnlyForEOA {uint public flag؛ // معدّل سيئ isNotContract (العنوان _a) {uint len؛ التجميع {len: = extcodesize (_a)} يتطلب (len == 0) ؛ _ ؛ } function setFlag (uint i) public isNotContract (msg.sender) {flag = i؛ }} عقد FakeEOA {مُنشئ (عنوان _a) عام {OnlyForEOA c = OnlyForEOA (_a)؛ c.setFlag (1) ؛ }} لغة الشفرة: JavaScript (javascript)
نظرًا لأنه يمكن حساب عناوين العقد مسبقًا ، فقد يفشل هذا الفحص أيضًا إذا تحقق من عنوان فارغ في الكتلة n ، ولكن تم نشر عقد فيه في كتلة ما أكبر من n.
تحذير: هذه المسألة دقيقة. إذا كان هدفك هو منع العقود الأخرى من الاتصال بعقدك ، فمن المحتمل أن يكون التحقق من حجم الشفرة كافياً. طريقة بديلة هي التحقق من قيمة (tx.origin == msg.sender) ، على الرغم من أن هذا أيضًا له عيوب.
قد تكون هناك حالات أخرى يخدم فيها التحقق من حجم الشفرة غرضك. وصف كل منهم هنا هو خارج النطاق. افهم السلوكيات الأساسية لـ EVM واستخدم حكمك.
هل كود بلوكشين الخاص بك آمن?
احجز فحصًا فوريًا لمدة يوم واحد مع خبراء الأمن لدينا. احجز اليوم اليقظةالأمنالعقود الذكيةالصلابةالرسالة الإخبارية اشترك في النشرة الإخبارية لدينا للحصول على أحدث أخبار Ethereum وحلول المؤسسات وموارد المطورين والمزيد.ندوة عبر الإنترنت
كيفية بناء منتج Blockchain ناجح
ندوة عبر الإنترنت
كيفية إعداد وتشغيل عقدة إيثريوم
ندوة عبر الإنترنت
كيفية بناء Ethereum API الخاصة بك
ندوة عبر الإنترنت
كيفية إنشاء رمز اجتماعي
ندوة عبر الإنترنت
استخدام أدوات الأمن في تطوير العقود الذكية
ندوة عبر الإنترنت