深入 SmartBugs 源码:从 CLI 参数到 Docker 任务调度的执行全流程
深入 SmartBugs 源码:从 CLI 参数到 Docker 任务调度的执行全流程
【免费下载链接】smartbugsSmartBugs: A Framework to Analyze Ethereum Smart Contracts项目地址: https://gitcode.com/gh_mirrors/smar/smartbugs
SmartBugs 是一个开源的以太坊智能合约安全分析框架,能够统一调度 Mythril、Slither、Oyente 等 30+ 分析工具。本文带你深入 SmartBugs 源码,完整梳理从命令行参数解析、配置合并、任务组装到 Docker 容器并行调度的执行全流程,帮助新手快速看懂框架内部运作机制。
SmartBugs 执行全流程:一张图看懂整体架构
SmartBugs 的源码核心位于sb/包中,整个执行链路可以浓缩为 6 个关键阶段:
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ CLI 入口 │──▶│ 配置合并 │──▶│ 文件收集 │──▶│ 任务组装 │──▶│ 并行调度 │──▶│ 结果解析 │ │ cli.py │ │settings │ │smartbugs│ │smartbugs│ │analysis │ │parsing │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ ▼ ▼ Docker 执行 结果文件 docker.py result.*每个阶段各司其职:sb/cli.py负责解析参数,sb/settings.py负责配置合并,sb/smartbugs.py负责文件收集与任务组装,sb/analysis.py负责多进程调度,sb/docker.py负责容器执行,sb/parsing.py负责结果标准化。
第一步:SmartBugs 入口与 CLI 参数解析
程序从哪里开始执行
SmartBugs 的入口非常简洁,无论是运行python -m sb还是直接执行smartbugs命令,最终都会调用sb/cli.py中的main()函数:
# sb/__main__.py import sb.cli if __name__ == "__main__": sb.cli.main()真正干活的是sb/cli.py中的cli_args()函数,它使用 Python 标准库argparse构建命令行解析器,并把参数划分为四个分组,逻辑非常清晰。
四大参数分组速览
- 输入选项(input):
-t/--tools指定分析工具、-f/--files指定合约文件(支持 glob 通配符和DIR:前缀)、-c/--configuration指定配置文件、--main只分析同名合约、--runtime分析部署后的字节码而非部署代码 - 执行选项(execution):
--processes设置并行进程数、--timeout设置每个任务的超时秒数、--cpu-quota与--mem-limit限制 Docker 容器资源、--continue-on-errors出错后继续执行 - 输出选项(output):
--runid设置运行标识、--results指定结果目录、--json输出解析后的 JSON、--sarif额外输出 SARIF 格式、--quiet静默模式 - 信息选项(information):
-v/--version显示版本、--debug开启调试日志
值得注意的是,cli_args()中凡是值为None的参数都会被丢弃,这正是"命令行参数优先级最高"这一设计的实现基础。
第二步:配置合并的优先级顺序与模板展开机制
三级配置的合并顺序
SmartBugs 的配置采用"低优先级在前、高优先级在后"的覆盖式合并,在sb/cli.py的cli()函数中实现:
- 站点级配置
site_cfg.yaml(项目根目录) - 用户级配置
~/.smartbugs/cfg.yaml - 命令行
-c指定的配置文件 - 命令行直接传入的参数(优先级最高)
freeze() 冻结与模板变量展开
配置合并完成后,sb/smartbugs.py的main()会调用settings.freeze()把所有模板变量一次性展开。默认的runid是${YEAR}${MONTH}${DAY}_${HOUR}${MIN},会自动替换成类似20260815_0840的时间戳;结果目录默认模板为results/${TOOL}/${RUNID}/${FILENAME},其中的$TOOL、$FILENAME等变量则留到生成每个任务时再逐个替换,相关实现见sb/settings.py的resultdir()方法。
第三步:工具加载与三种分析模式匹配
SmartBugs 之所以能统一调度众多工具,靠的是sb/tools.py的load()函数。每个工具在tools/<工具名>/config.yaml中声明自己的配置,例如 Mythril 的配置就同时声明了solidity、bytecode、runtime三种模式。
alias 别名机制
有些工具目录只是别名,比如tools/slither/config.yaml里只有一个alias: [slither-0.11.3],load()发现alias字段后会自动递归加载指向的真实工具配置,这就是为什么你可以在命令行中写slither而无需关心具体版本。
三种模式与文件类型的对应关系
solidity模式:分析.sol源码文件bytecode模式:分析.hex部署字节码runtime模式:分析.rt.hex运行时字节码(或使用--runtime参数)
另外,工具配置中的command和entrypoint是string.Template模板,执行时会把$FILENAME、$TIMEOUT、$BIN、$MAIN等变量替换为实际值,见sb/tools.py中的command()与entrypoint()方法。
第四步:文件收集与任务组装的完整过程
collect_files:匹配合约文件
sb/smartbugs.py的collect_files()用glob递归匹配文件模式,只接受.sol和.hex后缀,还支持.sbd清单文件——里面每一行是一个文件路径,可以批量列出待分析合约。
collect_tasks:文件 × 工具 = 任务
任务组装是框架的核心逻辑,简单说就是"每个文件 × 每个匹配模式的分析工具 = 一个任务":
- solc 版本匹配:对于
.sol文件,先通过sb/solidity.py提取 pragma 版本约束,再用sb/semantic_version.py匹配可用的编译器版本;匹配不到会直接报错 - 结果目录去重:多个任务可能生成相同的结果目录,
disambiguate()会自动追加_2、_3后缀解决冲突 - Docker 镜像预加载:
ensure_tool_is_loaded()会检查镜像是否已存在,不存在则先docker pull
第五步:多进程并行调度的核心实现
任务队列与工作进程
sb/analysis.py的run()是调度中枢,采用multiprocessing的spawn模式(保证 Linux 和 macOS 行为一致):
- 把所有任务随机打乱后放入任务队列,队尾放入 N 个
None哨兵 - 启动 N 个
analyser工作进程(N 即--processes参数) - 工作进程不断从队列取任务执行,遇到
None哨兵即退出
进度统计与 ETC 预估
框架还维护了tasks_started、tasks_completed、time_completed三个共享计数器,post_analysis()根据"已用时间 ÷ 已完成任务 × 剩余任务 ÷ 进程数"实时估算剩余完成时间(ETC),让你在跑大批量任务时心里有数。
第六步:Docker 容器中的任务执行细节
临时目录挂载与命令组装
sb/docker.py的execute()负责在容器内运行分析工具,细节非常讲究:
- 创建临时目录,把合约文件复制进去(字节码模式还会做
0x前缀清洗) - 将工具脚本目录
bin/和 solc 编译器一并复制到临时目录 - 临时目录以只读/读写方式挂载到容器的
/sb路径 - 默认禁用容器网络(
network: none),避免分析工具意外访问外网
超时控制与三连重试
容器运行后调用container.wait(timeout=...)实现超时控制,超时则强制stop。由于 Docker 偶发连接错误,sb/analysis.py的execute()还会在失败后等待 3~8 分钟再重试,最多重试 3 次。结束后容器会被kill和remove清理干净,不留垃圾进程。
第七步:结果解析、输出与常见参数速查
动态加载 parser 解析结果
分析完成后,sb/parsing.py会按工具动态加载对应的tools/<工具>/parser.py,把工具的原始输出(result.log和result.tar)解析成统一的findings / infos / errors / fails四类结果;开启--sarif时还会通过sb/sarif.py额外生成result.sarif文件,方便接入 CI 安全扫描流水线。
结果文件清单
每个任务的结果目录下最终会生成:result.log(工具日志)、result.tar(工具原始输出)、result.json(解析结果)、result.sarif(可选)、smartbugs.json(任务元数据)。
常用命令速查表
| 使用场景 | 推荐命令 |
|---|---|
| 单工具分析 | smartbugs -t mythril -f samples/0.8.24/SimpleDAO.sol |
| 多工具并行 | smartbugs -t mythril slither oyente -f samples/0.8.24/*.sol |
| 控制并行度 | 追加--processes 4 --timeout 600 |
| 输出解析结果 | 追加--json或--sarif |
| 覆盖重跑 | 追加--overwrite |
总结:SmartBugs 源码给我们的启发
回顾整个执行全流程,SmartBugs 源码的设计有三点很值得学习:插件化——新增一个分析工具只需在tools/下放一个config.yaml和parser.py;配置分层——站点、用户、命令行三级配置合并思路清晰;容器化隔离——所有分析工具都在 Docker 中运行,既保证了环境一致性,又通过超时和资源限制保护了宿主机。
如果你想亲手跑一遍源码,可以执行git clone https://gitcode.com/gh_mirrors/smar/smartbugs获取项目,然后按照doc/installation.md安装依赖,再对照本文的流程一步步打断点观察,相信你对智能合约安全分析框架的理解会再上一个台阶。
【免费下载链接】smartbugsSmartBugs: A Framework to Analyze Ethereum Smart Contracts项目地址: https://gitcode.com/gh_mirrors/smar/smartbugs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
