కాంట్రాక్ట్ పరిమాణ పరిమితిని ఎదుర్కోవడానికి కాంట్రాక్టులను తగ్గించడం
పరిమితి ఎందుకు ఉంది?
నవంబర్ 22, 2016 (opens in a new tab) నాడు, Spurious Dragon హార్డ్-ఫోర్క్ EIP-170 (opens in a new tab)ని ప్రవేశపెట్టింది, ఇది స్మార్ట్ కాంట్రాక్ట్ పరిమాణ పరిమితిని 24.576 kbగా చేర్చింది. ఒక Solidity డెవలపర్గా మీకు దీని అర్థం, మీరు మీ కాంట్రాక్టుకు మరింత ఎక్కువ కార్యాచరణను జోడించినప్పుడు, ఏదో ఒక సమయంలో మీరు పరిమితిని చేరుకుంటారు మరియు మోహరించేటప్పుడు ఈ లోపాన్ని చూస్తారు:
హెచ్చరిక: కాంట్రాక్ట్ కోడ్ పరిమాణం 24576 బైట్లను మించిపోయింది (Spurious Dragonలో ప్రవేశపెట్టిన పరిమితి). ఈ కాంట్రాక్ట్ Mainnetలో మోహరించదగినది కాకపోవచ్చు. ఆప్టిమైజర్ను ప్రారంభించడం (తక్కువ "runs" విలువతో!), రివర్ట్ స్ట్రింగ్లను ఆపివేయడం లేదా లైబ్రరీలను ఉపయోగించడం పరిగణించండి.
ఈ పరిమితి డినయల్-ఆఫ్-సర్వీస్ (DOS) దాడులను నిరోధించడానికి ప్రవేశపెట్టబడింది. ఒక కాంట్రాక్టుకు చేసే ఏ కాల్ అయినా గ్యాస్ పరంగా చాలా చౌకగా ఉంటుంది. అయినప్పటికీ, Ethereum నోడ్ల కోసం కాంట్రాక్ట్ కాల్ యొక్క ప్రభావం పిలిచే కాంట్రాక్ట్ కోడ్ పరిమాణాన్ని బట్టి (డిస్క్ నుండి కోడ్ను చదవడం, కోడ్ను ముందుగా ప్రాసెస్ చేయడం, మెర్కిల్ ప్రూఫ్కు డేటాను జోడించడం) అసమానంగా పెరుగుతుంది. దాడి చేసేవారికి ఇతరుల కోసం చాలా పని చేయడానికి కొన్ని వనరులు అవసరమయ్యే అటువంటి పరిస్థితి మీకు ఉన్నప్పుడల్లా, మీకు DOS దాడులకు ఆస్కారం ఉంటుంది.
నిజానికి ఇది అంత పెద్ద సమస్య కాదు, ఎందుకంటే ఒక సహజమైన కాంట్రాక్ట్ పరిమాణ పరిమితి బ్లాక్ గ్యాస్ పరిమితి. స్పష్టంగా, కాంట్రాక్ట్ యొక్క అన్ని బైట్కోడ్లను కలిగి ఉన్న లావాదేవీలో ఒక కాంట్రాక్టును మోహరించాలి. మీరు ఒక బ్లాక్లో ఆ ఒక్క లావాదేవీని మాత్రమే చేర్చినట్లయితే, మీరు ఆ గ్యాస్ మొత్తాన్ని ఉపయోగించుకోవచ్చు, కానీ అది అనంతం కాదు. లండన్ అప్గ్రేడ్ నుండి, నెట్వర్క్ డిమాండ్ను బట్టి బ్లాక్ గ్యాస్ పరిమితి 15M మరియు 30M యూనిట్ల మధ్య మారుతూ ఉంది.
కింది వాటిలో వాటి సంభావ్య ప్రభావం ఆధారంగా కొన్ని పద్ధతులను చూద్దాం. బరువు తగ్గడం పరంగా దీని గురించి ఆలోచించండి. ఎవరైనా వారి లక్ష్య బరువును (మా విషయంలో 24kb) చేరుకోవడానికి ఉత్తమ వ్యూహం మొదట పెద్ద ప్రభావ పద్ధతులపై దృష్టి పెట్టడం. చాలా సందర్భాలలో కేవలం మీ ఆహారాన్ని సరిచేసుకోవడం ద్వారా మీరు అక్కడికి చేరుకుంటారు, కానీ కొన్నిసార్లు మీకు కొంచెం ఎక్కువ అవసరం. అప్పుడు మీరు కొంత వ్యాయామం (మధ్యస్థ ప్రభావం) లేదా సప్లిమెంట్లను (చిన్న ప్రభావం) కూడా జోడించవచ్చు.
పెద్ద ప్రభావం
మీ కాంట్రాక్టులను వేరు చేయండి
ఇది ఎల్లప్పుడూ మీ మొదటి విధానం అయి ఉండాలి. మీరు కాంట్రాక్టును బహుళ చిన్నవిగా ఎలా వేరు చేయవచ్చు? ఇది సాధారణంగా మీ కాంట్రాక్టుల కోసం ఒక మంచి నిర్మాణాన్ని రూపొందించమని మిమ్మల్ని బలవంతం చేస్తుంది. కోడ్ చదవగలిగే దృక్కోణం నుండి చిన్న కాంట్రాక్టులకు ఎల్లప్పుడూ ప్రాధాన్యత ఇవ్వబడుతుంది. కాంట్రాక్టులను విభజించడానికి, మిమ్మల్ని మీరు ప్రశ్నించుకోండి:
- ఏ ఫంక్షన్లు కలిసి ఉంటాయి? ప్రతి ఫంక్షన్ల సెట్ దాని స్వంత కాంట్రాక్టులో ఉత్తమంగా ఉండవచ్చు.
- ఏ ఫంక్షన్లకు కాంట్రాక్ట్ స్థితిని చదవాల్సిన అవసరం లేదు లేదా స్థితి యొక్క నిర్దిష్ట ఉపసమితి మాత్రమే అవసరం?
- మీరు స్టోరేజ్ మరియు కార్యాచరణను విభజించగలరా?
లైబ్రరీలు
స్టోరేజ్ నుండి కార్యాచరణ కోడ్ను దూరంగా తరలించడానికి ఒక సులభమైన మార్గం లైబ్రరీ (opens in a new tab)ని ఉపయోగించడం. లైబ్రరీ ఫంక్షన్లను అంతర్గతంగా ప్రకటించవద్దు, ఎందుకంటే అవి కంపైలేషన్ సమయంలో నేరుగా కాంట్రాక్టుకు జోడించబడతాయి (opens in a new tab). కానీ మీరు పబ్లిక్ ఫంక్షన్లను ఉపయోగిస్తే, అవి వాస్తవానికి వేరే లైబ్రరీ కాంట్రాక్టులో ఉంటాయి. లైబ్రరీల వినియోగాన్ని మరింత సౌకర్యవంతంగా చేయడానికి using for (opens in a new tab)ని పరిగణించండి.
ప్రాక్సీలు
మరింత అధునాతన వ్యూహం ప్రాక్సీ వ్యవస్థ. లైబ్రరీలు వెనుక DELEGATECALLని ఉపయోగిస్తాయి, ఇది పిలుపు కాంట్రాక్ట్ స్థితితో మరొక కాంట్రాక్ట్ ఫంక్షన్ను అమలు చేస్తుంది. ప్రాక్సీ సిస్టమ్ల గురించి మరింత తెలుసుకోవడానికి ఈ బ్లాగ్ పోస్ట్ (opens in a new tab)ని చూడండి. అవి మీకు మరింత కార్యాచరణను అందిస్తాయి, ఉదాహరణకు, అవి అప్గ్రేడబిలిటీని ప్రారంభిస్తాయి, కానీ అవి చాలా సంక్లిష్టతను కూడా జోడిస్తాయి. ఏ కారణం చేతనైనా అది మీ ఏకైక ఎంపిక అయితే తప్ప, కాంట్రాక్ట్ పరిమాణాలను తగ్గించడానికి మాత్రమే నేను వాటిని జోడించను.
మధ్యస్థ ప్రభావం
ఫంక్షన్లను తొలగించండి
ఇది స్పష్టంగా ఉండాలి. ఫంక్షన్లు కాంట్రాక్ట్ పరిమాణాన్ని కొద్దిగా పెంచుతాయి.
- External: చాలా సార్లు మేము సౌలభ్యం కారణాల కోసం చాలా వీక్షణ ఫంక్షన్లను జోడిస్తాము. మీరు పరిమాణ పరిమితిని తాకే వరకు అది పూర్తిగా సరైనదే. అప్పుడు మీరు ఖచ్చితంగా అవసరమైనవి తప్ప మిగిలినవన్నీ తొలగించడం గురించి నిజంగా ఆలోచించాలనుకోవచ్చు.
- Internal: మీరు అంతర్గత/ప్రైవేట్ ఫంక్షన్లను కూడా తొలగించవచ్చు మరియు ఫంక్షన్ ఒక్కసారి మాత్రమే పిలువబడినంత కాలం కోడ్ను ఇన్లైన్ చేయవచ్చు.
అదనపు వేరియబుల్స్ను నివారించండి
function get(uint id) returns (address,address) {
MyStruct memory myStruct = myStructs[id];
return (myStruct.addr1, myStruct.addr2);
}
function get(uint id) returns (address,address) {
return (myStructs[id].addr1, myStructs[id].addr2);
}
ఇలాంటి ఒక సాధారణ మార్పు 0.28kb తేడాను కలిగిస్తుంది. మీ కాంట్రాక్టులలో ఇలాంటి అనేక పరిస్థితులను మీరు కనుగొనే అవకాశాలు ఉన్నాయి మరియు అవి నిజంగా గణనీయమైన మొత్తాలను జోడించగలవు.
లోప సందేశాన్ని సంక్షిప్తీకరించండి
సుదీర్ఘమైన రివర్ట్ సందేశాలు మరియు ముఖ్యంగా అనేక విభిన్న రివర్ట్ సందేశాలు కాంట్రాక్టును ఉబ్బిపోయేలా చేస్తాయి. బదులుగా చిన్న లోప కోడ్లను ఉపయోగించండి మరియు వాటిని మీ కాంట్రాక్టులో డీకోడ్ చేయండి. ఒక పొడవైన సందేశం చాలా చిన్నదిగా మారవచ్చు:
require(msg.sender == owner, "ఈ కాంట్రాక్ట్ యజమాని మాత్రమే ఈ ఫంక్షన్ను కాల్ చేయగలరు");
require(msg.sender == owner, "OW1");
లోప సందేశాలకు బదులుగా కస్టమ్ లోపాలను ఉపయోగించండి
Solidity 0.8.4 (opens in a new tab)లో కస్టమ్ లోపాలు ప్రవేశపెట్టబడ్డాయి. అవి మీ కాంట్రాక్టుల పరిమాణాన్ని తగ్గించడానికి ఒక గొప్ప మార్గం, ఎందుకంటే అవి సెలెక్టర్లుగా ABI-ఎన్కోడ్ చేయబడతాయి (ఫంక్షన్ల వలె).
error Unauthorized();
if (msg.sender != owner) {
revert Unauthorized();
}
ఆప్టిమైజర్లో తక్కువ రన్ విలువను పరిగణించండి
మీరు ఆప్టిమైజర్ సెట్టింగులను కూడా మార్చవచ్చు. 200 యొక్క డిఫాల్ట్ విలువ అంటే ఒక ఫంక్షన్ను 200 సార్లు పిలిచినట్లుగా బైట్కోడ్ను ఆప్టిమైజ్ చేయడానికి ప్రయత్నిస్తోంది. మీరు దానిని 1కి మార్చినట్లయితే, ప్రతి ఫంక్షన్ను ఒక్కసారి మాత్రమే అమలు చేసే సందర్భం కోసం ఆప్టిమైజ్ చేయమని మీరు ప్రాథమికంగా ఆప్టిమైజర్కు చెబుతారు. ఒక్కసారి మాత్రమే అమలు చేయడానికి ఆప్టిమైజ్ చేయబడిన ఫంక్షన్ అంటే అది మోహరింపు కోసమే ఆప్టిమైజ్ చేయబడింది. జాగ్రత్తగా ఉండండి, ఇది ఫంక్షన్లను అమలు చేయడానికి గ్యాస్ ఖర్చులను పెంచుతుంది, కాబట్టి మీరు దీన్ని చేయకూడదనుకోవచ్చు.
చిన్న ప్రభావం
ఫంక్షన్లకు స్ట్రక్ట్లను పంపడం మానుకోండి
మీరు ABIEncoderV2 (opens in a new tab)ని ఉపయోగిస్తుంటే, ఫంక్షన్కు స్ట్రక్ట్లను పంపకుండా ఉండటానికి ఇది సహాయపడుతుంది. పారామీటర్ను స్ట్రక్ట్గా పంపడానికి బదులుగా, అవసరమైన పారామీటర్లను నేరుగా పంపండి. ఈ ఉదాహరణలో మేము మరో 0.1kb ఆదా చేసాము.
function get(uint id) returns (address,address) {
return _get(myStruct);
}
function _get(MyStruct memory myStruct) private view returns(address,address) {
return (myStruct.addr1, myStruct.addr2);
}
function get(uint id) returns(address,address) {
return _get(myStructs[id].addr1, myStructs[id].addr2);
}
function _get(address addr1, address addr2) private view returns(address,address) {
return (addr1, addr2);
}
ఫంక్షన్లు మరియు వేరియబుల్స్ కోసం సరైన విజిబిలిటీని ప్రకటించండి
- బయటి నుండి మాత్రమే పిలువబడే ఫంక్షన్లు లేదా వేరియబుల్స్? వాటిని
publicబదులుగాexternalగా ప్రకటించండి. - కాంట్రాక్ట్ లోపలి నుండి మాత్రమే పిలువబడే ఫంక్షన్లు లేదా వేరియబుల్స్? వాటిని
publicబదులుగాprivateలేదాinternalగా ప్రకటించండి.
మాడిఫైయర్లను తొలగించండి
మాడిఫైయర్లు, ప్రత్యేకించి తీవ్రంగా ఉపయోగించినప్పుడు, కాంట్రాక్ట్ పరిమాణంపై గణనీయమైన ప్రభావాన్ని చూపుతాయి. వాటిని తొలగించి, బదులుగా ఫంక్షన్లను ఉపయోగించడం పరిగణించండి.
modifier checkStuff() {}
function doSomething() checkStuff {}
function checkStuff() private {}
function doSomething() { checkStuff(); }
ఆ చిట్కాలు కాంట్రాక్ట్ పరిమాణాన్ని గణనీయంగా తగ్గించడంలో మీకు సహాయపడతాయి. మరోసారి, నేను తగినంతగా నొక్కి చెప్పలేను, సాధ్యమైనంత వరకు అతిపెద్ద ప్రభావం కోసం కాంట్రాక్టులను విభజించడంపై ఎల్లప్పుడూ దృష్టి పెట్టండి.
పేజీ చివరి నవీకరణ: 3 ఏప్రిల్, 2026