是foundry还是foundry-zksync?揭秘foundry-devops基于FFI的版本探测技巧
【免费下载链接】foundry-devops 项目地址: https://gitcode.com/gh_mirrors/fo/foundry-devops
foundry-devops 是面向 Foundry 生态的 DevOps 工具箱:它既能从 broadcast 文件夹读取合约最近一次部署的地址,更核心的本领是基于 FFI 的版本探测——在测试运行期判断你当前用的是原版 foundry 还是 foundry-zksync 分支,让同一套测试代码在两套工具链之间无缝切换。本文带你用 3 步看懂这个巧妙的设计。
一、背景:为什么测试代码需要"分清楚"?
在测试 zkSync 合约时,开发者通常要面对两套工具链:
- Vanilla Foundry:官方版本,forge test 直接跑;
- foundry-zksync:Matter Labs 维护的分支版本,编译到 EraVM,forge test –zksync 执行。
问题在于:两者的"脾气"并不一样。比如 foundry-zksync 对 fork 支持不完整,一些 cheatcode 在编译到 EraVM 之后甚至无法被识别。如果测试代码不加区分地全部执行,必然有一边报错。
理想的状态是:一份测试代码,跑哪边都只执行自己该执行的部分,其余自动跳过。foundry-devops 就提供了这个能力,核心入口是 src/FoundryZkSyncChecker.sol 这个抽象合约。
二、核心技巧:让 Solidity 测试"跑 shell"拿版本号 🔍
关键观察:两个工具链的 forge –version 输出不同。
| Vanilla Foundry | forge 0.2.0 (…) | forge 0.2.0 |
| Vanilla Foundry | forge 0.3.0 (…) | forge 0.3.0 |
| foundry-zksync | forge 0.0.2 (…) | forge 0.0.2 |
"forge 0.0.2" 恰好是 11 个字节,于是探测逻辑非常简单:
这三个前缀在源码里以十六进制常量保存(其实就是 cast from-utf8 生成的 UTF-8 字节):
- FORGE_VERSION_0_0_2 = hex"666f72676520302e302e32" → 对应 forge 0.0.2(foundry-zksync)
- FORGE_VERSION_0_2_0、FORGE_VERSION_0_3_0 → 对应原版 foundry
命中 forge 0.0.2 就返回 true(是 foundry-zksync),命中 0.2.0 或 0.3.0 返回 false;如果两个都不是,直接 revert FoundryZkSyncChecker__UnknownFoundryVersion()——宁可报错也不误判,这一点很专业。
💡 这个技巧的妙处在于:探测逻辑完全跑在测试运行时,不依赖任何环境变量或配置开关,工具链"自报家门",天然无歧义。
三、上手使用:两个修饰符让测试自动分流
1. 前置配置:开启 FFI
FFI 默认是关闭的,需要在 foundry.toml 中加一行(项目里已经配置好了):
- ffi = true
2. 继承 FoundryZkSyncChecker,挂上修饰符
你的测试合约同时继承 Test 和 FoundryZkSyncChecker,然后给每个测试函数选择合适的修饰符:
- onlyFoundryZkSync:仅在 foundry-zksync 上执行
- onlyVanillaFoundry:仅在原版 foundry 上执行
看 test/ZkSyncChainCheckerLocalTest.t.sol 就很直观:同一个文件里,chainId 检测用例挂着 onlyVanillaFoundry,预编译探测用例挂着 onlyFoundryZkSync。跑 vanilla 就只跑前者,跑 zksync 就只跑后者,零人工干预。
3. 用 makefile 一键切换
项目自带的 makefile 提供了两个目标:
- make test:vanilla foundry 下执行 forge test
- make zktest:foundryup-zksync && forge test –zksync && foundryup,自动切到 zkSync 版再切回来
4. 交叉验证:bash 与 Solidity 互证
更严谨的是,项目还写了个纯 bash 版本 test/is_foundry_zksync.sh 做同样的版本探测(同样是解析 forge –version)。test/FoundryZkSyncCheckerTest.t.sol 会同时执行两条路径并断言结果一致——用"另一个独立实现"给 FFI 方案上了双保险 ✅
四、附赠能力:ZkSyncChainChecker 判断"链"而不是"工具"
foundry-devops 里还有另一个常被忽略的好东西:src/ZkSyncChainChecker.sol。它回答的问题不同——"我现在跑在 zkSync 链上吗?",用双保险策略:
- chainId 法:block.chainid 是否为 324(主网)/ 300(Sepolia)/ 260(内存节点);
- 预编译探针法:zkSync 不支持 0x03(RIPEMD-160)、0x04(identity)、0x05(modexp)、0x08(ecPairing)这几个预编译,直接 call 它们,失败即判定为 zkSync 链。
配套修饰符 skipZkSync(在 zkSync 上跳过)和 onlyZkSync(只在 zkSync 上执行),适合写跨链兼容的合约测试。
五、快速上手与注意事项 ⚠️
环境要求
- git、foundry(forge –version 可用)、jq
获取项目
git clone https://gitcode.com/gh_mirrors/fo/foundry-devops
cd foundry-devops
关键限制(来自 README)
项目文件导航
- 版本探测核心:src/FoundryZkSyncChecker.sol
- zkSync 链探测:src/ZkSyncChainChecker.sol
- 读取最近部署地址:src/DevOpsTools.sol(配合 fs_permissions 对 ./broadcast 目录的读权限)
- 测试与交叉验证:test/FoundryZkSyncCheckerTest.t.sol、test/is_foundry_zksync.sh
- 使用文档:README.md
六、总结
foundry-devops 的 FFI 版本探测技巧,本质是把"工具链自报家门"这件事做进了 Solidity 测试层:一次 vm.ffi 调用 + 11 字节前缀比对,就让测试代码获得了"环境感知"能力。对于同时维护 EVM 与 zkSync 测试的开发者来说,这是成本极低、收益极高的一招,值得放进你的 Solidity 工具包里 🚀
【免费下载链接】foundry-devops 项目地址: https://gitcode.com/gh_mirrors/fo/foundry-devops
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




