முக்கிய உள்ளடக்கத்திற்குச் செல்லவும்

ஸ்மார்ட் ஒப்பந்தங்களைச் சோதிக்க Echidna-ஐ எவ்வாறு பயன்படுத்துவது

Solidity
ஸ்மார்ட் ஒப்பந்தங்கள்
பாதுகாப்பு
சோதனை
ஃபஸ்ஸிங்
மேம்பட்ட
ட்ரெயில்ஆஃப்பிட்ஸ்
10 ஏப்ரல், 2020
11 நிமிட வாசிப்பு

நிறுவல்

Echidna-ஐ docker மூலமாகவோ அல்லது முன்-தொகுக்கப்பட்ட பைனரியைப் பயன்படுத்தியோ நிறுவலாம்.

docker மூலம் Echidna

docker pull trailofbits/eth-security-toolbox
docker run -it -v "$PWD":/home/training trailofbits/eth-security-toolbox

கடைசி கட்டளை eth-security-toolbox-ஐ உங்கள் தற்போதைய கோப்பகத்திற்கான அணுகலைக் கொண்ட ஒரு docker-இல் இயக்குகிறது. உங்கள் ஹோஸ்டிலிருந்து கோப்புகளை மாற்றலாம், மேலும் docker-இலிருந்து கோப்புகளில் கருவிகளை இயக்கலாம்

docker-இன் உள்ளே, இயக்கவும்:

solc-select 0.5.11
cd /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) என்பது பாதுகாப்பு சமூகத்தில் நன்கு அறியப்பட்ட ஒரு நுட்பமாகும். இது நிரலில் உள்ள பிழைகளைக் கண்டறிய அதிகமாகவோ அல்லது குறைவாகவோ சீரற்ற உள்ளீடுகளை உருவாக்குவதைக் கொண்டுள்ளது. பாரம்பரிய மென்பொருளுக்கான ஃபஸ்ஸர்கள் (AFL (opens in a new tab) அல்லது LibFuzzer (opens in a new tab) போன்றவை) பிழைகளைக் கண்டறியும் திறமையான கருவிகளாக அறியப்படுகின்றன.

உள்ளீடுகளை முற்றிலும் சீரற்ற முறையில் உருவாக்குவதைத் தாண்டி, நல்ல உள்ளீடுகளை உருவாக்க பல நுட்பங்களும் உத்திகளும் உள்ளன, அவற்றுள்:

  • ஒவ்வொரு செயல்பாட்டிலிருந்தும் பின்னூட்டத்தைப் பெற்று, அதைப் பயன்படுத்தி உருவாக்கத்தை வழிநடத்துதல். எடுத்துக்காட்டாக, புதிதாக உருவாக்கப்பட்ட உள்ளீடு ஒரு புதிய பாதையைக் கண்டறிய வழிவகுத்தால், அதற்கு நெருக்கமான புதிய உள்ளீடுகளை உருவாக்குவது அர்த்தமுள்ளதாக இருக்கும்.
  • கட்டமைப்பு கட்டுப்பாட்டை மதித்து உள்ளீட்டை உருவாக்குதல். எடுத்துக்காட்டாக, உங்கள் உள்ளீட்டில் செக்சம் (checksum) கொண்ட தலைப்பு இருந்தால், செக்சம்-ஐ சரிபார்க்கும் உள்ளீட்டை ஃபஸ்ஸரை உருவாக்க அனுமதிப்பது அர்த்தமுள்ளதாக இருக்கும்.
  • புதிய உள்ளீடுகளை உருவாக்க அறியப்பட்ட உள்ளீடுகளைப் பயன்படுத்துதல்: சரியான உள்ளீட்டின் பெரிய தரவுத்தொகுப்பிற்கான அணுகல் உங்களிடம் இருந்தால், உங்கள் ஃபஸ்ஸர் புதிதாக உருவாக்குவதைத் தொடங்குவதற்குப் பதிலாக, அவற்றிலிருந்து புதிய உள்ளீடுகளை உருவாக்க முடியும். இவை பொதுவாக விதைகள் (seeds) என்று அழைக்கப்படுகின்றன.

பண்பு அடிப்படையிலான ஃபஸ்ஸிங்

Echidna ஒரு குறிப்பிட்ட ஃபஸ்ஸர் குடும்பத்தைச் சேர்ந்தது: QuickCheck (opens in a new tab)-ஆல் பெரிதும் ஈர்க்கப்பட்ட பண்பு அடிப்படையிலான ஃபஸ்ஸிங். செயலிழப்புகளைக் கண்டறிய முயற்சிக்கும் கிளாசிக் ஃபஸ்ஸருக்கு மாறாக, Echidna பயனர் வரையறுத்த மாறிலிகளை (invariants) உடைக்க முயற்சிக்கும்.

ஸ்மார்ட் ஒப்பந்தங்களில், மாறிலிகள் என்பவை Solidity சார்புகள் ஆகும், அவை ஒப்பந்தம் அடையக்கூடிய எந்தவொரு தவறான அல்லது செல்லாத நிலையையும் குறிக்கலாம், அவற்றுள்:

  • தவறான அணுகல் கட்டுப்பாடு: தாக்குபவர் ஒப்பந்தத்தின் உரிமையாளராகிவிட்டார்.
  • தவறான நிலை இயந்திரம்: ஒப்பந்தம் இடைநிறுத்தப்பட்டிருக்கும் போது டோக்கன்களை மாற்ற முடியும்.
  • தவறான எண்கணிதம்: பயனர் தனது இருப்பை அண்டர்ஃப்ளோ (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 சார்புகள் ஆகும். ஒரு பண்பு:

  • எந்த வாதமும் (argument) கொண்டிருக்கக்கூடாது
  • அது வெற்றிகரமாக இருந்தால் true எனத் திரும்ப வேண்டும்
  • அதன் பெயர் echidna என்று தொடங்க வேண்டும்

Echidna செய்யும் செயல்கள்:

  • பண்பைச் சோதிக்க தன்னிச்சையான பரிவர்த்தனைகளைத் தானாகவே உருவாக்கும்.
  • ஒரு பண்பு 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) தேவை. உங்கள் ஒப்பந்தத்திற்கு ஒரு குறிப்பிட்ட துவக்கம் தேவைப்பட்டால், நீங்கள் அதை கட்டமைப்பாளரில் செய்ய வேண்டும்.

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()
...
அனைத்தையும் காட்டு

backdoor அழைக்கப்பட்டால் பண்பு மீறப்படுவதை Echidna கண்டறிந்தது.

ஃபஸ்ஸிங் பிரச்சாரத்தின் போது அழைக்க வேண்டிய சார்புகளை வடிகட்டுதல்

ஃபஸ் செய்ய வேண்டிய சார்புகளை எவ்வாறு வடிகட்டுவது என்பதைப் பார்ப்போம். இலக்கு பின்வரும் ஸ்மார்ட் ஒப்பந்தம்:

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) போன்ற குறியீட்டு செயலாக்கக் கருவியைப் பயன்படுத்த பரிந்துரைக்கப்படுகிறது). இதைச் சரிபார்க்க நாம் Echidna-ஐ இயக்கலாம்:

echidna-test multi.sol
...
echidna_state4: passed! 🎉
Seed: -3684648582249875403

சார்புகளை வடிகட்டுதல்

இந்த ஒப்பந்தத்தைச் சோதிக்க சரியான வரிசையைக் கண்டறிவதில் Echidna சிக்கலைக் கொண்டுள்ளது, ஏனெனில் இரண்டு மீட்டமைப்பு சார்புகளும் (reset1 மற்றும் reset2) அனைத்து நிலை மாறிகளையும் false என அமைக்கும். இருப்பினும், மீட்டமைப்பு சார்பை தடுப்புப்பட்டியலில் (blacklist) சேர்க்க அல்லது f, g, h மற்றும் i சார்புகளை மட்டும் அனுமதிப்பட்டியலில் (whitelist) சேர்க்க ஒரு சிறப்பு Echidna அம்சத்தைப் பயன்படுத்தலாம்.

சார்புகளைத் தடுப்புப்பட்டியலில் சேர்க்க, இந்த உள்ளமைவு கோப்பைப் பயன்படுத்தலாம்:

1filterBlacklist: true
2filterFunctions: ["reset1", "reset2"]

சார்புகளை வடிகட்டுவதற்கான மற்றொரு அணுகுமுறை அனுமதிப்பட்டியலில் உள்ள சார்புகளைப் பட்டியலிடுவதாகும். அதைச் செய்ய, இந்த உள்ளமைவு கோப்பைப் பயன்படுத்தலாம்:

1filterBlacklist: false
2filterFunctions: ["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: true
2filterFunctions: ["f1", "f2", "f3"]
echidna-test contract.sol --config config.yaml
...

filterBlacklist பூலியனின் மதிப்பைப் பொறுத்து, f1, f2 மற்றும் f3 ஆகியவற்றைத் தடுப்புப்பட்டியலில் சேர்த்து அல்லது இவற்றை மட்டுமே அழைத்து Echidna ஒரு ஃபஸ்ஸிங் பிரச்சாரத்தைத் தொடங்குகிறது.

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.yaml
Analyzing contract: assert.sol:Incrementor
assertion in inc: failed!💥
Call sequence, shrinking (2596/5000):
inc(21711016731996786641919559689128982722488122124807605757398297001483711807488)
inc(7237005577332262213973186563042994240829374041602535252466099000494570602496)
inc(86844066927987146567678238756515930889952488499230423029593188005934847229952)
Seed: 1806480648350826486
அனைத்தையும் காட்டு

நீங்கள் பார்ப்பது போல், inc சார்பில் சில வலியுறுத்தல் தோல்விகளை Echidna புகாரளிக்கிறது. ஒரு சார்புக்கு ஒன்றுக்கு மேற்பட்ட வலியுறுத்தல்களைச் சேர்ப்பது சாத்தியமாகும், ஆனால் எந்த வலியுறுத்தல் தோல்வியடைந்தது என்பதை Echidna-ஆல் கூற முடியாது.

வலியுறுத்தல்களை எப்போது, எப்படிப் பயன்படுத்துவது

வெளிப்படையான பண்புகளுக்கு மாற்றாக வலியுறுத்தல்களைப் பயன்படுத்தலாம், குறிப்பாகச் சரிபார்க்க வேண்டிய நிபந்தனைகள் சில செயல்பாடு f-இன் சரியான பயன்பாட்டுடன் நேரடியாகத் தொடர்புடையதாக இருந்தால். சில குறியீடுகளுக்குப் பிறகு வலியுறுத்தல்களைச் சேர்ப்பது, அது செயல்படுத்தப்பட்ட உடனேயே சரிபார்ப்பு நடக்கும் என்பதைச் செயல்படுத்தும்:

1function f(..) public {
2 // சில சிக்கலான குறியீடு
3 ...
4 assert (condition);
5 ...
6}
7

மாறாக, வெளிப்படையான echidna பண்பைப் பயன்படுத்துவது பரிவர்த்தனைகளைச் சீரற்ற முறையில் செயல்படுத்தும், மேலும் அது எப்போது சரிபார்க்கப்படும் என்பதைச் சரியாகச் செயல்படுத்த எளிதான வழி இல்லை. இந்தத் தீர்வைச் செய்வது இன்னும் சாத்தியமாகும்:

1function echidna_assert_after_f() public returns (bool) {
2 f(..);
3 return(condition);
4}

இருப்பினும், சில சிக்கல்கள் உள்ளன:

  • f ஆனது internal அல்லது external என அறிவிக்கப்பட்டால் அது தோல்வியடையும்.
  • f-ஐ அழைக்க எந்த வாதங்களைப் பயன்படுத்த வேண்டும் என்பது தெளிவாக இல்லை.
  • f திரும்பினால் (reverts), பண்பு தோல்வியடையும்.

பொதுவாக, வலியுறுத்தல்களை எவ்வாறு பயன்படுத்துவது என்பது குறித்த ஜான் ரெகரின் பரிந்துரையைப் (John Regehr's recommendation) (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.yaml
Analyzing contract: assert.sol:Incrementor
assertion in inc: failed!💥
Call sequence, shrinking (2596/5000):
inc(21711016731996786641919559689128982722488122124807605757398297001483711807488)
inc(7237005577332262213973186563042994240829374041602535252466099000494570602496)
inc(86844066927987146567678238756515930889952488499230423029593188005934847229952)
Seed: 1806480648350826486
அனைத்தையும் காட்டு

பெரிய வாதங்களுடன் இந்தச் சார்பு பல முறை அழைக்கப்பட்டால் inc-இல் உள்ள வலியுறுத்தல் தோல்வியடையும் என்பதை Echidna கண்டறிந்தது.

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: true
2corpusDir: "corpus-magic"

இப்போது நாம் எங்கள் கருவியை இயக்கலாம் மற்றும் சேகரிக்கப்பட்ட கார்பஸைச் சரிபார்க்கலாம்:

echidna-test magic.sol --config config.yaml

Echidna-ஆல் இன்னும் சரியான மேஜிக் மதிப்புகளைக் கண்டறிய முடியவில்லை, ஆனால் அது சேகரித்த கார்பஸை நாம் பார்க்கலாம். எடுத்துக்காட்டாக, இந்தக் கோப்புகளில் ஒன்று:

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]
அனைத்தையும் காட்டு

தெளிவாக, இந்த உள்ளீடு எங்கள் பண்பில் தோல்வியைத் தூண்டாது. இருப்பினும், அடுத்த கட்டத்தில், அதற்காக அதை எவ்வாறு மாற்றுவது என்பதைப் பார்ப்போம்.

கார்பஸை விதைத்தல்

magic சார்பைக் கையாள Echidna-க்கு சில உதவிகள் தேவை. அதற்கான பொருத்தமான அளவுருக்களைப் பயன்படுத்த உள்ளீட்டை நகலெடுத்து மாற்றப் போகிறோம்:

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: 142
Unique codehashes: 1
Seed: -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 else
13 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.sol
2...
3echidna_test: passed! 🎉
4
5Seed: 2320549945714142710

எரிவாயு நுகர்வை அளவிடுதல்

Echidna மூலம் எரிவாயு நுகர்வை இயக்க, ஒரு உள்ளமைவு கோப்பை config.yaml உருவாக்கவும்:

1estimateGas: true

இந்த எடுத்துக்காட்டில், முடிவுகளைப் புரிந்துகொள்வதை எளிதாக்க பரிவர்த்தனை வரிசையின் அளவையும் குறைப்போம்:

1seqLen: 2
2estimateGas: true

Echidna-ஐ இயக்குதல்

உள்ளமைவு கோப்பை உருவாக்கியதும், நாம் 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: 157
Unique codehashes: 1
Seed: -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.yaml
2...
3pop used a maximum of 10746 gas
4...
5check used a maximum of 23730 gas
6...
7clear used a maximum of 35916 gas
8...
9push used a maximum of 40839 gas
அனைத்தையும் காட்டு

அதற்குக் காரணம், செலவு addrs-இன் அளவைப் பொறுத்தது மற்றும் சீரற்ற அழைப்புகள் வரிசையை (array) கிட்டத்தட்ட காலியாக விட முனைகின்றன. இருப்பினும், pop மற்றும் clear-ஐத் தடுப்புப்பட்டியலில் சேர்ப்பது எங்களுக்குச் சிறந்த முடிவுகளைத் தருகிறது:

1filterBlacklist: true
2filterFunctions: ["pop", "clear"]
1echidna-test pushpop.sol --config config.yaml
2...
3push used a maximum of 40839 gas
4...
5check used a maximum of 1484472 gas

சுருக்கம்: அதிக எரிவாயு நுகர்வு கொண்ட பரிவர்த்தனைகளைக் கண்டறிதல்

estimateGas உள்ளமைவு விருப்பத்தைப் பயன்படுத்தி அதிக எரிவாயு நுகர்வு கொண்ட பரிவர்த்தனைகளை Echidna கண்டறிய முடியும்:

1estimateGas: true
echidna-test contract.sol --config config.yaml
...

ஃபஸ்ஸிங் பிரச்சாரம் முடிந்ததும், ஒவ்வொரு சார்புக்கும் அதிகபட்ச எரிவாயு நுகர்வு கொண்ட வரிசையை Echidna புகாரளிக்கும்.

பக்கம் கடைசியாகப் புதுப்பிக்கப்பட்டது: 21 அக்டோபர், 2025

இந்த வழிகாட்டி பயனுள்ளதாக இருந்ததா?