اسمارٹ کانٹریکٹس کو ٹیسٹ کرنے کے لیے Echidna کا استعمال کیسے کریں
انسٹالیشن
Echidna کو ڈوکر (docker) کے ذریعے یا پہلے سے مرتب شدہ (pre-compiled) بائنری کا استعمال کرتے ہوئے انسٹال کیا جا سکتا ہے۔
ڈوکر کے ذریعے Echidna
docker pull trailofbits/eth-security-toolboxdocker run -it -v "$PWD":/home/training trailofbits/eth-security-toolboxآخری کمانڈ eth-security-toolbox کو ایک ڈوکر میں چلاتی ہے جسے آپ کی موجودہ ڈائرکٹری تک رسائی حاصل ہوتی ہے۔ آپ اپنے ہوسٹ سے فائلیں تبدیل کر سکتے ہیں، اور ڈوکر سے فائلوں پر ٹولز چلا سکتے ہیں
ڈوکر کے اندر، چلائیں:
solc-select 0.5.11cd /home/trainingبائنری
https://github.com/crytic/echidna/releases/tag/v1.4.0.0 (opens in a new tab)
پراپرٹی پر مبنی فزنگ کا تعارف
Echidna ایک پراپرٹی پر مبنی فزر (fuzzer) ہے، جسے ہم نے اپنی پچھلی بلاگ پوسٹس میں بیان کیا ہے (1 (opens in a new tab)، 2 (opens in a new tab)، 3 (opens in a new tab))۔
فزنگ
فزنگ (Fuzzing) (opens in a new tab) سیکیورٹی کمیونٹی میں ایک مشہور تکنیک ہے۔ یہ پروگرام میں بگز تلاش کرنے کے لیے کم و بیش بے ترتیب (random) ان پٹس بنانے پر مشتمل ہے۔ روایتی سافٹ ویئر کے لیے فزرز (جیسے AFL (opens in a new tab) یا LibFuzzer (opens in a new tab)) بگز تلاش کرنے کے لیے موثر ٹولز کے طور پر جانے جاتے ہیں۔
ان پٹس کی خالصتاً بے ترتیب تخلیق کے علاوہ، اچھے ان پٹس بنانے کے لیے بہت سی تکنیکیں اور حکمت عملیاں ہیں، جن میں شامل ہیں:
- ہر عمل درآمد (execution) سے فیڈ بیک حاصل کریں اور اس کا استعمال کرتے ہوئے تخلیق کی رہنمائی کریں۔ مثال کے طور پر، اگر ایک نیا بنایا گیا ان پٹ کسی نئے راستے کی دریافت کا باعث بنتا ہے، تو اس کے قریب نئے ان پٹس بنانا معنی خیز ہو سکتا ہے۔
- ساختی رکاوٹ (structural constraint) کا احترام کرتے ہوئے ان پٹ بنانا۔ مثال کے طور پر، اگر آپ کے ان پٹ میں چیک سم (checksum) کے ساتھ ہیڈر شامل ہے، تو فزر کو چیک سم کی توثیق کرنے والا ان پٹ بنانے دینا معنی خیز ہوگا۔
- نئے ان پٹس بنانے کے لیے معلوم ان پٹس کا استعمال: اگر آپ کو درست ان پٹ کے بڑے ڈیٹاسیٹ تک رسائی حاصل ہے، تو آپ کا فزر شروع سے تخلیق کرنے کے بجائے ان سے نئے ان پٹس بنا سکتا ہے۔ انہیں عام طور پر سیڈز (seeds) کہا جاتا ہے۔
پراپرٹی پر مبنی فزنگ
Echidna فزر کے ایک مخصوص خاندان سے تعلق رکھتا ہے: پراپرٹی پر مبنی فزنگ جو QuickCheck (opens in a new tab) سے بہت زیادہ متاثر ہے۔ کلاسک فزر کے برعکس جو کریشز تلاش کرنے کی کوشش کرے گا، Echidna صارف کے بیان کردہ انویرینٹس (invariants) کو توڑنے کی کوشش کرے گا۔
اسمارٹ کانٹریکٹس میں، انویرینٹس Solidity فنکشنز ہوتے ہیں، جو کسی بھی غلط یا نامانوس اسٹیٹ کی نمائندگی کر سکتے ہیں جہاں کانٹریکٹ پہنچ سکتا ہے، بشمول:
- غلط ایکسیس کنٹرول: حملہ آور کانٹریکٹ کا مالک بن گیا۔
- غلط اسٹیٹ مشین: کانٹریکٹ کے موقوف (paused) ہونے کے دوران ٹوکنز منتقل کیے جا سکتے ہیں۔
- غلط ریاضی: صارف اپنے بیلنس کو انڈرفلو (underflow) کر سکتا ہے اور لامحدود مفت ٹوکنز حاصل کر سکتا ہے۔
Echidna کے ساتھ پراپرٹی کی ٹیسٹنگ
ہم دیکھیں گے کہ Echidna کے ساتھ اسمارٹ کانٹریکٹ کو کیسے ٹیسٹ کیا جائے۔ ہدف درج ذیل اسمارٹ کانٹریکٹ token.sol (opens in a new tab) ہے:
1contract Token{2 mapping(address => uint) public balances;3 function airdrop() public{4 balances[msg.sender] = 1000;5 }6 function consume() public{7 require(balances[msg.sender]>0);8 balances[msg.sender] -= 1;9 }10 function backdoor() public{11 balances[msg.sender] += 1;12 }13}ہم یہ فرض کریں گے کہ اس ٹوکن میں درج ذیل خصوصیات ہونی چاہئیں:
- کسی کے پاس بھی زیادہ سے زیادہ 1000 ٹوکنز ہو سکتے ہیں
- ٹوکن منتقل نہیں کیا جا سکتا (یہ ERC-20 ٹوکن نہیں ہے)
پراپرٹی لکھیں
Echidna پراپرٹیز Solidity فنکشنز ہیں۔ ایک پراپرٹی کو لازمی طور پر:
- کوئی آرگومنٹ نہیں ہونا چاہیے
- اگر یہ کامیاب ہو تو
trueواپس کرنا چاہیے - اس کا نام
echidnaسے شروع ہونا چاہیے
Echidna کرے گا:
- پراپرٹی کو ٹیسٹ کرنے کے لیے خود بخود صوابدیدی (arbitrary) ٹرانزیکشنز بنائے گا۔
- کسی بھی ایسی ٹرانزیکشن کی اطلاع دے گا جس کی وجہ سے پراپرٹی
falseواپس کرے یا کوئی ایرر دے۔ - پراپرٹی کو کال کرتے وقت سائیڈ ایفیکٹ کو مسترد کر دے گا (یعنی، اگر پراپرٹی کسی اسٹیٹ ویری ایبل کو تبدیل کرتی ہے، تو اسے ٹیسٹ کے بعد مسترد کر دیا جاتا ہے)
درج ذیل پراپرٹی چیک کرتی ہے کہ کال کرنے والے کے پاس 1000 سے زیادہ ٹوکنز نہیں ہیں:
1function echidna_balance_under_1000() public view returns(bool){2 return balances[msg.sender] <= 1000;3}اپنے کانٹریکٹ کو اپنی پراپرٹیز سے الگ کرنے کے لیے وراثت (inheritance) کا استعمال کریں:
1contract TestToken is Token{2 function echidna_balance_under_1000() public view returns(bool){3 return balances[msg.sender] <= 1000;4 }5 }token.sol (opens in a new tab) پراپرٹی کو نافذ کرتا ہے اور ٹوکن سے وراثت حاصل کرتا ہے۔
کانٹریکٹ شروع کریں
Echidna کو بغیر آرگومنٹ کے ایک کنسٹرکٹر (constructor) کی ضرورت ہوتی ہے۔ اگر آپ کے کانٹریکٹ کو مخصوص ابتدا (initialization) کی ضرورت ہے، تو آپ کو اسے کنسٹرکٹر میں کرنے کی ضرورت ہے۔
Echidna میں کچھ مخصوص ایڈریسز ہیں:
0x00a329c0648769A73afAc7F9381E08FB43dBEA72جو کنسٹرکٹر کو کال کرتا ہے۔0x10000،0x20000، اور0x00a329C0648769a73afAC7F9381e08fb43DBEA70جو تصادفی طور پر دوسرے فنکشنز کو کال کرتے ہیں۔
ہمیں اپنی موجودہ مثال میں کسی خاص ابتدا کی ضرورت نہیں ہے، جس کے نتیجے میں ہمارا کنسٹرکٹر خالی ہے۔
Echidna چلائیں
Echidna کو اس کے ساتھ لانچ کیا جاتا ہے:
echidna-test contract.solاگر contract.sol میں متعدد کانٹریکٹس ہیں، تو آپ ہدف بتا سکتے ہیں:
echidna-test contract.sol --contract MyContractخلاصہ: پراپرٹی کی ٹیسٹنگ
درج ذیل ہماری مثال پر echidna کے چلنے کا خلاصہ کرتا ہے:
1contract TestToken is Token{2 constructor() public {}3 function echidna_balance_under_1000() public view returns(bool){4 return balances[msg.sender] <= 1000;5 }6 }echidna-test testtoken.sol --contract TestToken...
echidna_balance_under_1000: failed!💥 Call sequence, shrinking (1205/5000): airdrop() backdoor()
...Echidna نے پایا کہ اگر backdoor کو کال کیا جائے تو پراپرٹی کی خلاف ورزی ہوتی ہے۔
فزنگ مہم کے دوران کال کرنے کے لیے فنکشنز کو فلٹر کرنا
ہم دیکھیں گے کہ فز کیے جانے والے فنکشنز کو کیسے فلٹر کیا جائے۔ ہدف درج ذیل اسمارٹ کانٹریکٹ ہے:
1contract C {2 bool state1 = false;3 bool state2 = false;4 bool state3 = false;5 bool state4 = false;6
7 function f(uint x) public {8 require(x == 12);9 state1 = true;10 }11
12 function g(uint x) public {13 require(state1);14 require(x == 8);15 state2 = true;16 }17
18 function h(uint x) public {19 require(state2);20 require(x == 42);21 state3 = true;22 }23
24 function i() public {25 require(state3);26 state4 = true;27 }28
29 function reset1() public {30 state1 = false;31 state2 = false;32 state3 = false;33 return;34 }35
36 function reset2() public {37 state1 = false;38 state2 = false;39 state3 = false;40 return;41 }42
43 function echidna_state4() public returns (bool) {44 return (!state4);45 }46}یہ چھوٹی سی مثال Echidna کو اسٹیٹ ویری ایبل کو تبدیل کرنے کے لیے ٹرانزیکشنز کی ایک خاص ترتیب تلاش کرنے پر مجبور کرتی ہے۔ یہ ایک فزر کے لیے مشکل ہے (یہ تجویز کیا جاتا ہے کہ Manticore (opens in a new tab) جیسا علامتی عمل درآمد (symbolic execution) ٹول استعمال کریں)۔ ہم اس کی تصدیق کے لیے Echidna چلا سکتے ہیں:
echidna-test multi.sol...echidna_state4: passed! 🎉Seed: -3684648582249875403فنکشنز کو فلٹر کرنا
Echidna کو اس کانٹریکٹ کو ٹیسٹ کرنے کے لیے صحیح ترتیب تلاش کرنے میں دشواری ہوتی ہے کیونکہ دو ری سیٹ فنکشنز (reset1 اور reset2) تمام اسٹیٹ ویری ایبلز کو false پر سیٹ کر دیں گے۔
تاہم، ہم ری سیٹ فنکشن کو بلیک لسٹ کرنے یا صرف f، g،
h اور i فنکشنز کو وائٹ لسٹ کرنے کے لیے ایک خاص Echidna فیچر استعمال کر سکتے ہیں۔
فنکشنز کو بلیک لسٹ کرنے کے لیے، ہم یہ کنفیگریشن فائل استعمال کر سکتے ہیں:
1filterBlacklist: true2filterFunctions: ["reset1", "reset2"]فنکشنز کو فلٹر کرنے کا دوسرا طریقہ وائٹ لسٹ کیے گئے فنکشنز کی فہرست بنانا ہے۔ ایسا کرنے کے لیے، ہم یہ کنفیگریشن فائل استعمال کر سکتے ہیں:
1filterBlacklist: false2filterFunctions: ["f", "g", "h", "i"]filterBlacklistپہلے سے طے شدہ طور پرtrueہے۔- فلٹرنگ صرف نام سے کی جائے گی (پیرامیٹرز کے بغیر)۔ اگر آپ کے پاس
f()اورf(uint256)ہیں، تو فلٹر"f"دونوں فنکشنز سے مماثل ہوگا۔
Echidna چلائیں
کنفیگریشن فائل blacklist.yaml کے ساتھ Echidna چلانے کے لیے:
echidna-test multi.sol --config blacklist.yaml...echidna_state4: failed!💥 Call sequence: f(12) g(8) h(42) i()Echidna پراپرٹی کو غلط ثابت کرنے کے لیے ٹرانزیکشنز کی ترتیب تقریباً فوراً تلاش کر لے گا۔
خلاصہ: فنکشنز کو فلٹر کرنا
Echidna فزنگ مہم کے دوران کال کرنے کے لیے فنکشنز کو بلیک لسٹ یا وائٹ لسٹ کر سکتا ہے، اس کا استعمال کرتے ہوئے:
1filterBlacklist: true2filterFunctions: ["f1", "f2", "f3"]echidna-test contract.sol --config config.yaml...Echidna filterBlacklist بولین (boolean) کی قدر کے مطابق، یا تو f1، f2 اور f3 کو بلیک لسٹ کر کے یا صرف انہیں کال کر کے فزنگ مہم شروع کرتا ہے۔
Echidna کے ساتھ Solidity کے assert کو کیسے ٹیسٹ کریں
اس مختصر ٹیوٹوریل میں، ہم یہ دکھانے جا رہے ہیں کہ کانٹریکٹس میں اسیرشن (assertion) چیکنگ کو ٹیسٹ کرنے کے لیے Echidna کا استعمال کیسے کریں۔ فرض کریں کہ ہمارے پاس اس طرح کا ایک کانٹریکٹ ہے:
1contract Incrementor {2 uint private counter = 2**200;3
4 function inc(uint val) public returns (uint){5 uint tmp = counter;6 counter += val;7 // tmp، counter سے کم یا اس کے برابر ہے8 return (counter - tmp);9 }10}ایک اسیرشن لکھیں
ہم یہ یقینی بنانا چاہتے ہیں کہ اس کا فرق واپس کرنے کے بعد tmp counter سے کم یا اس کے برابر ہے۔ ہم ایک Echidna پراپرٹی لکھ سکتے ہیں، لیکن ہمیں tmp کی قدر کو کہیں اسٹور کرنے کی ضرورت ہوگی۔ اس کے بجائے، ہم اس طرح کا ایک اسیرشن استعمال کر سکتے ہیں:
1contract Incrementor {2 uint private counter = 2**200;3
4 function inc(uint val) public returns (uint){5 uint tmp = counter;6 counter += val;7 assert (tmp <= counter);8 return (counter - tmp);9 }10}Echidna چلائیں
اسیرشن کی ناکامی کی ٹیسٹنگ کو فعال کرنے کے لیے، ایک Echidna کنفیگریشن فائل (opens in a new tab) config.yaml بنائیں:
1checkAsserts: trueجب ہم اس کانٹریکٹ کو Echidna میں چلاتے ہیں، تو ہمیں متوقع نتائج حاصل ہوتے ہیں:
echidna-test assert.sol --config config.yamlAnalyzing contract: assert.sol:Incrementorassertion in inc: failed!💥 Call sequence, shrinking (2596/5000): inc(21711016731996786641919559689128982722488122124807605757398297001483711807488) inc(7237005577332262213973186563042994240829374041602535252466099000494570602496) inc(86844066927987146567678238756515930889952488499230423029593188005934847229952)
Seed: 1806480648350826486جیسا کہ آپ دیکھ سکتے ہیں، Echidna inc فنکشن میں کچھ اسیرشن کی ناکامی کی اطلاع دیتا ہے۔ فی فنکشن ایک سے زیادہ اسیرشن شامل کرنا ممکن ہے، لیکن Echidna یہ نہیں بتا سکتا کہ کون سا اسیرشن ناکام ہوا۔
اسیرشنز کب اور کیسے استعمال کریں
اسیرشنز کو واضح پراپرٹیز کے متبادل کے طور پر استعمال کیا جا سکتا ہے، خاص طور پر اگر چیک کی جانے والی شرائط کا براہ راست تعلق کسی آپریشن f کے درست استعمال سے ہو۔ کچھ کوڈ کے بعد اسیرشنز شامل کرنے سے یہ نافذ ہو جائے گا کہ چیک اس کے عمل میں آنے کے فوراً بعد ہوگا۔:
1function f(..) public {2 // کچھ پیچیدہ کوڈ3 ...4 assert (condition);5 ...6}7
اس کے برعکس، ایک واضح echidna پراپرٹی کا استعمال تصادفی طور پر ٹرانزیکشنز کو انجام دے گا اور یہ نافذ کرنے کا کوئی آسان طریقہ نہیں ہے کہ اسے کب چیک کیا جائے گا۔ یہ ورک اراؤنڈ (workaround) کرنا اب بھی ممکن ہے:
1function echidna_assert_after_f() public returns (bool) {2 f(..);3 return(condition);4}تاہم، کچھ مسائل ہیں:
- اگر
fکوinternalیاexternalکے طور پر ڈکلیئر کیا گیا ہو تو یہ ناکام ہو جاتا ہے۔ - یہ واضح نہیں ہے کہ
fکو کال کرنے کے لیے کون سے آرگومنٹس استعمال کیے جائیں۔ - اگر
fریورٹ (revert) ہوتا ہے، تو پراپرٹی ناکام ہو جائے گی۔
عام طور پر، ہم اسیرشنز کے استعمال کے طریقہ کار پر John Regehr کی سفارش (opens in a new tab) پر عمل کرنے کی تجویز کرتے ہیں:
- اسیرشن چیکنگ کے دوران کسی بھی سائیڈ ایفیکٹ پر مجبور نہ کریں۔ مثال کے طور پر:
assert(ChangeStateAndReturn() == 1) - واضح بیانات پر زور نہ دیں۔ مثال کے طور پر
assert(var >= 0)جہاںvarکوuintکے طور پر ڈکلیئر کیا گیا ہے۔
آخر میں، براہ کرم assert کے بجائے require کا استعمال نہ کریں، کیونکہ Echidna اس کا پتہ لگانے کے قابل نہیں ہوگا (لیکن کانٹریکٹ بہرحال ریورٹ ہو جائے گا)۔
خلاصہ: اسیرشن چیکنگ
درج ذیل ہماری مثال پر echidna کے چلنے کا خلاصہ کرتا ہے:
1contract Incrementor {2 uint private counter = 2**200;3
4 function inc(uint val) public returns (uint){5 uint tmp = counter;6 counter += val;7 assert (tmp <= counter);8 return (counter - tmp);9 }10}echidna-test assert.sol --config config.yamlAnalyzing contract: assert.sol:Incrementorassertion in inc: failed!💥 Call sequence, shrinking (2596/5000): inc(21711016731996786641919559689128982722488122124807605757398297001483711807488) inc(7237005577332262213973186563042994240829374041602535252466099000494570602496) inc(86844066927987146567678238756515930889952488499230423029593188005934847229952)
Seed: 1806480648350826486Echidna نے پایا کہ inc میں اسیرشن ناکام ہو سکتا ہے اگر اس فنکشن کو بڑے آرگومنٹس کے ساتھ کئی بار کال کیا جائے۔
Echidna کارپس کو جمع کرنا اور اس میں ترمیم کرنا
ہم دیکھیں گے کہ Echidna کے ساتھ ٹرانزیکشنز کا کارپس (corpus) کیسے جمع کیا جائے اور استعمال کیا جائے۔ ہدف درج ذیل اسمارٹ کانٹریکٹ magic.sol (opens in a new tab) ہے:
1contract C {2 bool value_found = false;3 function magic(uint magic_1, uint magic_2, uint magic_3, uint magic_4) public {4 require(magic_1 == 42);5 require(magic_2 == 129);6 require(magic_3 == magic_4+333);7 value_found = true;8 return;9 }10
11 function echidna_magic_values() public returns (bool) {12 return !value_found;13 }14
15}یہ چھوٹی سی مثال Echidna کو اسٹیٹ ویری ایبل کو تبدیل کرنے کے لیے کچھ اقدار تلاش کرنے پر مجبور کرتی ہے۔ یہ ایک فزر کے لیے مشکل ہے (یہ تجویز کیا جاتا ہے کہ Manticore (opens in a new tab) جیسا علامتی عمل درآمد ٹول استعمال کریں)۔ ہم اس کی تصدیق کے لیے Echidna چلا سکتے ہیں:
echidna-test magic.sol...
echidna_magic_values: passed! 🎉
Seed: 2221503356319272685تاہم، ہم اب بھی اس فزنگ مہم کو چلاتے وقت کارپس جمع کرنے کے لیے Echidna کا استعمال کر سکتے ہیں۔
کارپس جمع کرنا
کارپس جمع کرنے کو فعال کرنے کے لیے، ایک کارپس ڈائرکٹری بنائیں:
mkdir corpus-magicاور ایک Echidna کنفیگریشن فائل (opens in a new tab) config.yaml:
1coverage: true2corpusDir: "corpus-magic"اب ہم اپنا ٹول چلا سکتے ہیں اور جمع کیے گئے کارپس کو چیک کر سکتے ہیں:
echidna-test magic.sol --config config.yamlEchidna اب بھی صحیح جادوئی اقدار (magic values) تلاش نہیں کر سکتا، لیکن ہم اس کے جمع کردہ کارپس پر ایک نظر ڈال سکتے ہیں۔ مثال کے طور پر، ان فائلوں میں سے ایک تھی:
1[2 {3 "_gas'": "0xffffffff",4 "_delay": ["0x13647", "0xccf6"],5 "_src": "00a329c0648769a73afac7f9381e08fb43dbea70",6 "_dst": "00a329c0648769a73afac7f9381e08fb43dbea72",7 "_value": "0x0",8 "_call": {9 "tag": "SolCall",10 "contents": [11 "magic",12 [13 {14 "contents": [15 256,16 "93723985220345906694500679277863898678726808528711107336895287282192244575836"17 ],18 "tag": "AbiUInt"19 },20 {21 "contents": [256, "334"],22 "tag": "AbiUInt"23 },24 {25 "contents": [26 256,27 "68093943901352437066264791224433559271778087297543421781073458233697135179558"28 ],29 "tag": "AbiUInt"30 },31 {32 "tag": "AbiUInt",33 "contents": [256, "332"]34 }35 ]36 ]37 },38 "_gasprice'": "0xa904461f1"39 }40]واضح طور پر، یہ ان پٹ ہماری پراپرٹی میں ناکامی کو متحرک نہیں کرے گا۔ تاہم، اگلے مرحلے میں، ہم دیکھیں گے کہ اس کے لیے اس میں کیسے ترمیم کی جائے۔
کارپس کو سیڈ کرنا
Echidna کو magic فنکشن سے نمٹنے کے لیے کچھ مدد کی ضرورت ہے۔ ہم اس کے لیے مناسب پیرامیٹرز استعمال کرنے کے لیے ان پٹ کو کاپی اور تبدیل کرنے جا رہے ہیں:
cp corpus/2712688662897926208.txt corpus/new.txtہم magic(42,129,333,0) کو کال کرنے کے لیے new.txt میں ترمیم کریں گے۔ اب، ہم Echidna کو دوبارہ چلا سکتے ہیں:
echidna-test magic.sol --config config.yaml...echidna_magic_values: failed!💥 Call sequence: magic(42,129,333,0)
Unique instructions: 142Unique codehashes: 1Seed: -7293830866560616537
اس بار، اس نے پایا کہ پراپرٹی کی فوری طور پر خلاف ورزی ہوئی ہے۔
زیادہ گیس کی کھپت والی ٹرانزیکشنز تلاش کرنا
ہم دیکھیں گے کہ Echidna کے ساتھ زیادہ گیس کی کھپت والی ٹرانزیکشنز کیسے تلاش کی جائیں۔ ہدف درج ذیل اسمارٹ کانٹریکٹ ہے:
1contract C {2 uint state;3
4 function expensive(uint8 times) internal {5 for(uint8 i=0; i < times; i++)6 state = state + i;7 }8
9 function f(uint x, uint y, uint8 times) public {10 if (x == 42 && y == 123)11 expensive(times);12 else13 state = 0;14 }15
16 function echidna_test() public returns (bool) {17 return true;18 }19
20}یہاں expensive میں گیس کی بڑی کھپت ہو سکتی ہے۔
فی الحال، Echidna کو ٹیسٹ کرنے کے لیے ہمیشہ ایک پراپرٹی کی ضرورت ہوتی ہے: یہاں echidna_test ہمیشہ true واپس کرتا ہے۔
ہم اس کی تصدیق کے لیے Echidna چلا سکتے ہیں:
1echidna-test gas.sol2...3echidna_test: passed! 🎉4
5Seed: 2320549945714142710گیس کی کھپت کی پیمائش
Echidna کے ساتھ گیس کی کھپت کو فعال کرنے کے لیے، ایک کنفیگریشن فائل config.yaml بنائیں:
1estimateGas: trueاس مثال میں، ہم نتائج کو سمجھنے میں آسان بنانے کے لیے ٹرانزیکشن کی ترتیب کا سائز بھی کم کریں گے:
1seqLen: 22estimateGas: trueEchidna چلائیں
ایک بار جب ہم کنفیگریشن فائل بنا لیتے ہیں، تو ہم Echidna کو اس طرح چلا سکتے ہیں:
echidna-test gas.sol --config config.yaml...echidna_test: passed! 🎉
f used a maximum of 1333608 gas Call sequence: f(42,123,249) Gas price: 0x10d5733f0a Time delay: 0x495e5 Block delay: 0x88b2
Unique instructions: 157Unique codehashes: 1Seed: -325611019680165325
- دکھائی گئی گیس ایک تخمینہ ہے جو HEVM (opens in a new tab) کے ذریعہ فراہم کیا گیا ہے۔
گیس کم کرنے والی کالز کو فلٹر کرنا
اوپر فزنگ مہم کے دوران کال کرنے کے لیے فنکشنز کو فلٹر کرنے کا ٹیوٹوریل دکھاتا ہے کہ آپ کی ٹیسٹنگ سے کچھ فنکشنز کو کیسے ہٹایا جائے۔
گیس کا درست تخمینہ حاصل کرنے کے لیے یہ اہم ہو سکتا ہے۔
درج ذیل مثال پر غور کریں:
1contract C {2 address [] addrs;3 function push(address a) public {4 addrs.push(a);5 }6 function pop() public {7 addrs.pop();8 }9 function clear() public{10 addrs.length = 0;11 }12 function check() public{13 for(uint256 i = 0; i < addrs.length; i++)14 for(uint256 j = i+1; j < addrs.length; j++)15 if (addrs[i] == addrs[j])16 addrs[j] = address(0x0);17 }18 function echidna_test() public returns (bool) {19 return true;20 }21}اگر Echidna تمام فنکشنز کو کال کر سکتا ہے، تو اسے زیادہ گیس کی لاگت والی ٹرانزیکشنز آسانی سے نہیں ملیں گی:
1echidna-test pushpop.sol --config config.yaml2...3pop used a maximum of 10746 gas4...5check used a maximum of 23730 gas6...7clear used a maximum of 35916 gas8...9push used a maximum of 40839 gasاس کی وجہ یہ ہے کہ لاگت کا انحصار addrs کے سائز پر ہوتا ہے اور بے ترتیب کالز ارے (array) کو تقریباً خالی چھوڑ دیتی ہیں۔
تاہم، pop اور clear کو بلیک لسٹ کرنے سے ہمیں بہت بہتر نتائج ملتے ہیں:
1filterBlacklist: true2filterFunctions: ["pop", "clear"]1echidna-test pushpop.sol --config config.yaml2...3push used a maximum of 40839 gas4...5check used a maximum of 1484472 gasخلاصہ: زیادہ گیس کی کھپت والی ٹرانزیکشنز تلاش کرنا
Echidna estimateGas کنفیگریشن آپشن کا استعمال کرتے ہوئے زیادہ گیس کی کھپت والی ٹرانزیکشنز تلاش کر سکتا ہے:
1estimateGas: trueechidna-test contract.sol --config config.yaml...فزنگ مہم ختم ہونے کے بعد، Echidna ہر فنکشن کے لیے زیادہ سے زیادہ گیس کی کھپت کے ساتھ ایک ترتیب کی اطلاع دے گا۔
صفحہ کی آخری اپ ڈیٹ: ۳ مارچ، ۲۰۲۶