স্মার্ট কন্ট্রাক্ট বাগ খুঁজতে স্লিদার (Slither) কীভাবে ব্যবহার করবেন
স্লিদার কীভাবে ব্যবহার করবেন
এই টিউটোরিয়ালের উদ্দেশ্য হলো স্মার্ট কন্ট্রাক্টে স্বয়ংক্রিয়ভাবে বাগ খুঁজতে স্লিদার কীভাবে ব্যবহার করতে হয় তা দেখানো।
- ইন্সটলেশন
- কমান্ড লাইন ব্যবহার
- স্ট্যাটিক অ্যানালাইসিসের পরিচিতি: স্ট্যাটিক অ্যানালাইসিসের সংক্ষিপ্ত পরিচিতি
- এপিআই (API): পাইথন এপিআই-এর বিবরণ
ইন্সটলেশন
স্লিদার ব্যবহার করার জন্য Python >= 3.6 প্রয়োজন। এটি pip বা docker ব্যবহার করে ইন্সটল করা যেতে পারে।
pip-এর মাধ্যমে স্লিদার:
pip3 install --user slither-analyzer
docker-এর মাধ্যমে স্লিদার:
docker pull trailofbits/eth-security-toolbox
docker run -it -v "$PWD":/home/trufflecon trailofbits/eth-security-toolbox
শেষ কমান্ডটি একটি ডকারে eth-security-toolbox চালায় যার আপনার বর্তমান ডিরেক্টরিতে অ্যাক্সেস রয়েছে। আপনি আপনার হোস্ট থেকে ফাইলগুলো পরিবর্তন করতে পারেন এবং ডকার থেকে ফাইলগুলোর উপর টুলগুলো চালাতে পারেন
ডকারের ভিতরে, রান করুন:
solc-select 0.5.11
cd /home/trufflecon/
স্ক্রিপ্ট রান করা
python 3 দিয়ে একটি পাইথন স্ক্রিপ্ট রান করতে:
python3 script.py
কমান্ড লাইন
কমান্ড লাইন বনাম ব্যবহারকারী-নির্ধারিত স্ক্রিপ্ট। স্লিদার পূর্বনির্ধারিত ডিটেক্টরের একটি সেট নিয়ে আসে যা অনেক সাধারণ বাগ খুঁজে বের করে। কমান্ড লাইন থেকে স্লিদার কল করলে সমস্ত ডিটেক্টর রান হবে, এর জন্য স্ট্যাটিক অ্যানালাইসিসের বিস্তারিত জ্ঞানের প্রয়োজন নেই:
slither project_paths
ডিটেক্টর ছাড়াও, স্লিদারে এর printers (opens in a new tab) এবং tools (opens in a new tab)-এর মাধ্যমে কোড রিভিউ করার ক্ষমতা রয়েছে।
প্রাইভেট ডিটেক্টর এবং GitHub ইন্টিগ্রেশনে অ্যাক্সেস পেতে crytic.io (opens in a new tab) ব্যবহার করুন।
স্ট্যাটিক অ্যানালাইসিস
স্লিদার স্ট্যাটিক অ্যানালাইসিস ফ্রেমওয়ার্কের ক্ষমতা এবং ডিজাইন ব্লগ পোস্টে (1 (opens in a new tab), 2 (opens in a new tab)) এবং একটি একাডেমিক পেপারে (opens in a new tab) বর্ণনা করা হয়েছে।
স্ট্যাটিক অ্যানালাইসিস বিভিন্ন ধরনের হয়ে থাকে। আপনি সম্ভবত বুঝতে পেরেছেন যে clang (opens in a new tab) এবং gcc (opens in a new tab)-এর মতো কম্পাইলারগুলো এই গবেষণার কৌশলগুলোর উপর নির্ভর করে, তবে এটি (Infer (opens in a new tab), CodeClimate (opens in a new tab), FindBugs (opens in a new tab)-এর মতো টুল এবং Frama-C (opens in a new tab) ও Polyspace (opens in a new tab)-এর মতো ফরমাল মেথডের উপর ভিত্তি করে তৈরি টুলগুলোরও ভিত্তি।
আমরা এখানে স্ট্যাটিক অ্যানালাইসিস কৌশল এবং গবেষকদের নিয়ে বিস্তারিত আলোচনা করব না। এর পরিবর্তে, স্লিদার কীভাবে কাজ করে তা বোঝার জন্য যা প্রয়োজন আমরা তার উপর ফোকাস করব, যাতে আপনি বাগ খুঁজতে এবং কোড বুঝতে এটি আরও কার্যকরভাবে ব্যবহার করতে পারেন।
কোড রিপ্রেজেন্টেশন
ডাইনামিক অ্যানালাইসিসের বিপরীতে, যা একটি একক এক্সিকিউশন পাথ নিয়ে কাজ করে, স্ট্যাটিক অ্যানালাইসিস একই সাথে সমস্ত পাথ নিয়ে কাজ করে। এটি করার জন্য, এটি একটি ভিন্ন কোড রিপ্রেজেন্টেশনের উপর নির্ভর করে। সবচেয়ে সাধারণ দুটি হলো অ্যাবস্ট্রাক্ট সিনট্যাক্স ট্রি (AST) এবং কন্ট্রোল ফ্লো গ্রাফ (CFG)।
অ্যাবস্ট্রাক্ট সিনট্যাক্স ট্রি (AST)
কম্পাইলার যখনই কোড পার্স করে তখনই AST ব্যবহার করা হয়। এটি সম্ভবত সবচেয়ে মৌলিক কাঠামো যার উপর স্ট্যাটিক অ্যানালাইসিস করা যেতে পারে।
সংক্ষেপে, একটি AST হলো একটি স্ট্রাকচার্ড ট্রি যেখানে সাধারণত প্রতিটি লিফে একটি ভেরিয়েবল বা কনস্ট্যান্ট থাকে এবং ইন্টারনাল নোডগুলো হলো অপারেন্ড বা কন্ট্রোল ফ্লো অপারেশন। নিচের কোডটি বিবেচনা করুন:
function safeAdd(uint a, uint b) pure internal returns(uint){
if(a + b <= a){
revert();
}
return a + b;
}
এর সাথে সম্পর্কিত AST নিচে দেখানো হলো:
স্লিদার solc দ্বারা এক্সপোর্ট করা AST ব্যবহার করে।
তৈরি করা সহজ হলেও, AST হলো একটি নেস্টেড স্ট্রাকচার। অনেক সময়, এটি বিশ্লেষণ করা সবচেয়ে সহজ কাজ নয়। উদাহরণস্বরূপ, a + b <= a এক্সপ্রেশন দ্বারা ব্যবহৃত অপারেশনগুলো শনাক্ত করতে, আপনাকে প্রথমে <= এবং তারপর + বিশ্লেষণ করতে হবে। একটি সাধারণ পদ্ধতি হলো তথাকথিত ভিজিটর প্যাটার্ন ব্যবহার করা, যা ট্রির মাধ্যমে রিকার্সিভভাবে নেভিগেট করে। স্লিদারে ExpressionVisitor (opens in a new tab)-এ একটি জেনেরিক ভিজিটর রয়েছে।
নিচের কোডটি এক্সপ্রেশনে কোনো যোগ (addition) আছে কিনা তা শনাক্ত করতে ExpressionVisitor ব্যবহার করে:
from slither.visitors.expression.expression import ExpressionVisitor
from slither.core.expressions.binary_operation import BinaryOperationType
class HasAddition(ExpressionVisitor):
def result(self):
return self._result
def _post_binary_operation(self, expression):
if expression.type == BinaryOperationType.ADDITION:
self._result = True
visitor = HasAddition(expression) # expression হলো সেই এক্সপ্রেশন যা টেস্ট করা হবে
print(f'The expression {expression} has a addition: {visitor.result()}')
কন্ট্রোল ফ্লো গ্রাফ (CFG)
দ্বিতীয় সবচেয়ে সাধারণ কোড রিপ্রেজেন্টেশন হলো কন্ট্রোল ফ্লো গ্রাফ (CFG)। নাম থেকেই বোঝা যায়, এটি একটি গ্রাফ-ভিত্তিক রিপ্রেজেন্টেশন যা সমস্ত এক্সিকিউশন পাথ প্রকাশ করে। প্রতিটি নোডে এক বা একাধিক ইন্সট্রাকশন থাকে। গ্রাফের এজগুলো কন্ট্রোল ফ্লো অপারেশন (if/then/else, loop ইত্যাদি) উপস্থাপন করে। আমাদের আগের উদাহরণের CFG হলো:
CFG হলো সেই রিপ্রেজেন্টেশন যার উপর ভিত্তি করে বেশিরভাগ অ্যানালাইসিস তৈরি করা হয়।
আরও অনেক কোড রিপ্রেজেন্টেশন রয়েছে। আপনি যে অ্যানালাইসিস করতে চান তার উপর ভিত্তি করে প্রতিটি রিপ্রেজেন্টেশনের সুবিধা এবং অসুবিধা রয়েছে।
অ্যানালাইসিস
স্লিদার দিয়ে আপনি যে সবচেয়ে সহজ ধরনের অ্যানালাইসিস করতে পারেন তা হলো সিনট্যাকটিক অ্যানালাইসিস।
সিনট্যাক্স অ্যানালাইসিস
স্লিদার প্যাটার্ন ম্যাচিং-এর মতো পদ্ধতি ব্যবহার করে অসঙ্গতি এবং ত্রুটি খুঁজে বের করতে কোডের বিভিন্ন উপাদান এবং তাদের রিপ্রেজেন্টেশনের মাধ্যমে নেভিগেট করতে পারে।
উদাহরণস্বরূপ, নিচের ডিটেক্টরগুলো সিনট্যাক্স-সম্পর্কিত সমস্যাগুলো খোঁজে:
-
স্টেট ভেরিয়েবল শ্যাডোয়িং (opens in a new tab): সমস্ত স্টেট ভেরিয়েবলের উপর ইটারেট করে এবং চেক করে যে কোনোটি ইনহেরিট করা কন্ট্রাক্ট থেকে কোনো ভেরিয়েবলকে শ্যাডো করে কিনা (state.py#L51-L62 (opens in a new tab))
-
ভুল ERC20 ইন্টারফেস (opens in a new tab): ভুল ERC20 ফাংশন সিগনেচার খোঁজে (incorrect_erc20_interface.py#L34-L55 (opens in a new tab))
সিমেন্টিক অ্যানালাইসিস
সিনট্যাক্স অ্যানালাইসিসের বিপরীতে, একটি সিমেন্টিক অ্যানালাইসিস আরও গভীরে যাবে এবং কোডের "অর্থ" বিশ্লেষণ করবে। এই পরিবারে কিছু বিস্তৃত ধরনের অ্যানালাইসিস অন্তর্ভুক্ত রয়েছে। এগুলো আরও শক্তিশালী এবং দরকারী ফলাফলের দিকে নিয়ে যায়, তবে এগুলো লেখাও আরও জটিল।
সবচেয়ে উন্নত দুর্বলতা শনাক্তকরণের জন্য সিমেন্টিক অ্যানালাইসিস ব্যবহার করা হয়।
ডেটা ডিপেন্ডেন্সি অ্যানালাইসিস
একটি ভেরিয়েবল variable_a-কে variable_b-এর ডেটা-ডিপেন্ডেন্ট বলা হয় যদি এমন কোনো পাথ থাকে যার জন্য variable_a-এর মান variable_b দ্বারা প্রভাবিত হয়।
নিচের কোডে, variable_a হলো variable_b-এর উপর নির্ভরশীল:
// ...
variable_a = variable_b + 1;
স্লিদারে বিল্ট-ইন ডেটা ডিপেন্ডেন্সি (opens in a new tab) ক্ষমতা রয়েছে, এর ইন্টারমিডিয়েট রিপ্রেজেন্টেশনের কারণে (পরবর্তী বিভাগে আলোচনা করা হয়েছে)।
ডেটা ডিপেন্ডেন্সি ব্যবহারের একটি উদাহরণ বিপজ্জনক স্ট্রিক্ট ইকুয়ালিটি ডিটেক্টরে (opens in a new tab) পাওয়া যেতে পারে। এখানে স্লিদার একটি বিপজ্জনক মানের সাথে স্ট্রিক্ট ইকুয়ালিটি তুলনা খুঁজবে (incorrect_strict_equality.py#L86-L87 (opens in a new tab)), এবং ব্যবহারকারীকে জানাবে যে কোনো আক্রমণকারীকে কন্ট্রাক্টটি ফাঁদে ফেলা থেকে বিরত রাখতে ==-এর পরিবর্তে >= বা <= ব্যবহার করা উচিত। অন্যান্য বিষয়ের মধ্যে, ডিটেক্টরটি balanceOf(address)-এ কলের রিটার্ন ভ্যালুকে বিপজ্জনক হিসেবে বিবেচনা করবে (incorrect_strict_equality.py#L63-L64 (opens in a new tab)), এবং এর ব্যবহার ট্র্যাক করতে ডেটা ডিপেন্ডেন্সি ইঞ্জিন ব্যবহার করবে।
ফিক্সড-পয়েন্ট কম্পিউটেশন
যদি আপনার অ্যানালাইসিস CFG-এর মাধ্যমে নেভিগেট করে এবং এজগুলো অনুসরণ করে, তবে আপনি সম্ভবত ইতিমধ্যে ভিজিট করা নোডগুলো দেখতে পাবেন। উদাহরণস্বরূপ, যদি নিচে দেখানো লুপটি উপস্থিত থাকে:
for(uint i; i < range; ++){
variable_a += 1
}
আপনার অ্যানালাইসিসকে জানতে হবে কখন থামতে হবে। এখানে দুটি প্রধান কৌশল রয়েছে: (1) প্রতিটি নোডে একটি নির্দিষ্ট সংখ্যক বার ইটারেট করা, (2) একটি তথাকথিত ফিক্সপয়েন্ট গণনা করা। একটি ফিক্সপয়েন্ট মূলত বোঝায় যে এই নোডটি বিশ্লেষণ করা কোনো অর্থপূর্ণ তথ্য প্রদান করে না।
রিএন্ট্রান্সি ডিটেক্টরগুলোতে ব্যবহৃত ফিক্সপয়েন্টের একটি উদাহরণ পাওয়া যেতে পারে: স্লিদার নোডগুলো এক্সপ্লোর করে এবং এক্সটার্নাল কল, স্টোরেজে রাইট এবং রিড খোঁজে। একবার এটি একটি ফিক্সপয়েন্টে পৌঁছালে (reentrancy.py#L125-L131 (opens in a new tab)), এটি এক্সপ্লোরেশন থামিয়ে দেয় এবং বিভিন্ন রিএন্ট্রান্সি প্যাটার্নের মাধ্যমে কোনো রিএন্ট্রান্সি উপস্থিত আছে কিনা তা দেখতে ফলাফলগুলো বিশ্লেষণ করে (reentrancy_benign.py (opens in a new tab), reentrancy_read_before_write.py (opens in a new tab), reentrancy_eth.py (opens in a new tab))।
দক্ষ ফিক্সড পয়েন্ট কম্পিউটেশন ব্যবহার করে অ্যানালাইসিস লেখার জন্য অ্যানালাইসিস কীভাবে এর তথ্য প্রচার করে সে সম্পর্কে ভালো ধারণা থাকা প্রয়োজন।
ইন্টারমিডিয়েট রিপ্রেজেন্টেশন
একটি ইন্টারমিডিয়েট রিপ্রেজেন্টেশন (IR) হলো এমন একটি ভাষা যা মূল ভাষার চেয়ে স্ট্যাটিক অ্যানালাইসিসের জন্য বেশি উপযোগী। স্লিদার সলিডিটিকে এর নিজস্ব IR-এ অনুবাদ করে: SlithIR (opens in a new tab)।
আপনি যদি শুধুমাত্র বেসিক চেক লিখতে চান তবে SlithIR বোঝার প্রয়োজন নেই। তবে, আপনি যদি উন্নত সিমেন্টিক অ্যানালাইসিস লেখার পরিকল্পনা করেন তবে এটি কাজে আসবে। SlithIR (opens in a new tab) এবং SSA (opens in a new tab) প্রিন্টারগুলো আপনাকে কোড কীভাবে অনুবাদ করা হয় তা বুঝতে সাহায্য করবে।
এপিআই (API) বেসিকস
স্লিদারে একটি API রয়েছে যা আপনাকে কন্ট্রাক্ট এবং এর ফাংশনগুলোর বেসিক অ্যাট্রিবিউটগুলো এক্সপ্লোর করতে দেয়।
একটি কোডবেস লোড করতে:
from slither import Slither
slither = Slither('/path/to/project')
কন্ট্রাক্ট এবং ফাংশন এক্সপ্লোর করা
একটি Slither অবজেক্টে থাকে:
contracts (list(Contract): কন্ট্রাক্টের তালিকাcontracts_derived (list(Contract): এমন কন্ট্রাক্টের তালিকা যা অন্য কোনো কন্ট্রাক্ট দ্বারা ইনহেরিট করা হয়নি (কন্ট্রাক্টের সাবসেট)get_contract_from_name (str): নাম থেকে একটি কন্ট্রাক্ট রিটার্ন করে
একটি Contract অবজেক্টে থাকে:
name (str): কন্ট্রাক্টের নামfunctions (list(Function)): ফাংশনের তালিকাmodifiers (list(Modifier)): ফাংশনের তালিকাall_functions_called (list(Function/Modifier)): কন্ট্রাক্ট দ্বারা পৌঁছানো যায় এমন সমস্ত ইন্টারনাল ফাংশনের তালিকাinheritance (list(Contract)): ইনহেরিট করা কন্ট্রাক্টের তালিকাget_function_from_signature (str): সিগনেচার থেকে একটি ফাংশন রিটার্ন করেget_modifier_from_signature (str): সিগনেচার থেকে একটি মডিফায়ার রিটার্ন করেget_state_variable_from_name (str): নাম থেকে একটি StateVariable রিটার্ন করে
একটি Function বা Modifier অবজেক্টে থাকে:
name (str): ফাংশনের নামcontract (contract): যে কন্ট্রাক্টে ফাংশনটি ডিক্লেয়ার করা হয়েছেnodes (list(Node)): ফাংশন/মডিফায়ারের CFG গঠনকারী নোডগুলোর তালিকাentry_point (Node): CFG-এর এন্ট্রি পয়েন্টvariables_read (list(Variable)): রিড করা ভেরিয়েবলের তালিকাvariables_written (list(Variable)): রাইট করা ভেরিয়েবলের তালিকাstate_variables_read (list(StateVariable)): রিড করা স্টেট ভেরিয়েবলের তালিকা (variables`read-এর সাবসেট)state_variables_written (list(StateVariable)): রাইট করা স্টেট ভেরিয়েবলের তালিকা (variables`written-এর সাবসেট)
পেজ সর্বশেষ আপডেট করা হয়েছে: 15 এপ্রিল, 2026

