
Solidity 合约库链接怎么做用 --libraries 填充占位符并避免手工链接字节码【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity用 Solidity 命令线编译器solc编译一个调用了库library的合约时输出的字节码不会包含库的真实地址而是留下一串形如__$53aea86b7d70b31448b230b20ae141a537$__的占位符。这类字节码是不完整的文档明确说明should not be deployed必须先完成链接linking把占位符替换成库的实际部署地址。本文讲一条可执行的路径在编译时用solc --libraries填充占位符如果你已经拿到了未链接的二进制文档也给出了补救手段但同时解释了为什么手工改写字节码不推荐。以下内容以仓库中的 Using the CompilerLibrary Linking 小节L69-L108和 Libraries 为准。占位符长什么样怎么对应到库在确认链接结果之前先要知道占位符的构成否则无法核对占位符是库的全限定名fully qualified name做 keccak256 哈希后十六进制编码的前34 个字符外面包着__$...$__。全限定名 库所在源文件路径 : 库名例如库放在libraries/目录的bigint.sol中、名为BigInt则全限定名是libraries/bigint.sol:BigInt。用-o把二进制写到文件时字节码文件末尾会附带形如// placeholder - fq library name的注释行用来标明每个占位符对应哪个库。核对时可以直接看这些行。0.5.0之前的编译器使用过旧格式直接以全限定名作为占位符现在编译器不再输出旧格式。主路径编译时用 --libraries 填充占位符文档推荐的做法是让编译器在编译时完成链接。有两种传参方式方式一把地址直接写在命令行solc --bin --libraries file.sol:Math0x1234567890123456789012345678901234567890 sourceFile.sol多个库用逗号或空格分隔写在同一个--libraries值里solc --bin --libraries file.sol:Math0x1234567890123456789012345678901234567890 file.sol:Heap0xabCD567890123456789012345678901234567890 sourceFile.sol上面的0x1234...是文档给出的示例地址实际使用时替换为你已部署的库合约地址。库在 Solidity 中的定位是一次性部署到某个地址、代码通过DELEGATECALL被复用所以这里填的就是库的部署地址在合约代码中也可以用address(LibraryName)把这个地址转出来核对。分隔符有一个版本约定从 Solidity 0.8.1 起库名与地址之间以作为分隔符旧的:分隔已弃用、文档说明未来会移除--libraries file.sol:Math:0x1234...目前仍可用。新脚本里直接用。方式二把库地址存到文件文档同时支持one library per line的库文件方式文件内容按同样的文件路径:库名地址语法一行一个库例如file.sol:Math0x1234567890123456789012345678901234567890 file.sol:Heap0xabCD567890123456789012345678901234567890然后solc --bin --libraries libs.txt sourceFile.sol库较多或构建流程自动化时文件方式比拼接长字符串更可控。替代路径standard JSON 的 libraries 键solc --standard-json从标准输入读 JSON、从标准输出返回 JSON是文档推荐的更复杂、尤其是自动化场景的接口。链接地址写在settings.libraries中{ settings: { libraries: { myFile.sol: { MyLib: 0x123123... } } } }其中0x123123...是文档示例的省略写法实际传入完整地址。文档对这个键有三个明确约束顶层键是库所在的源文件名如果用了 import remapping这个路径要匹配 remapping 应用后的全局路径顶层键为空字符串时表示全局层级如果这里没有给全所有库输出就是未链接对象且output data is different同一编译会输出不同的未链接数据。对应地输出 JSON 中evm.bytecode和evm.deployedBytecode会带一个linkReferences字段文档原话是 If given, this is an unlinked objectlinkReferences: { libraryFile.sol: { Library1: [ { start: 0, length: 20 }, { start: 200, length: 20 } ] } }它给出的是字节码内的字节偏移链接就是在这些位置替换 20 字节。这也是后文验证的抓手。一个容易踩的格式差异合约元数据里的libraries字段与 standard JSON 输入格式不同——元数据用的是扁平键例如MyLib.sol:MyLib: 0x123123...见 metadata.rst。如果你要解析或对比元数据里的库地址注意别按 standard JSON 的嵌套结构去读。可选补救对已编译的二进制执行 solc --link如果手里已经是未链接的二进制hex 编码、带__$...$__占位符solc --link可以事后链接。它的行为由文档限定得很死用之前要清楚所有输入文件都被解释为未链接的二进制做就地链接如果输入来自 stdin结果写到 stdout此模式下除--libraries之外的所有选项包括-o都被忽略链接地址仍然通过--libraries提供语法与编译时相同。另外旧的全限定名直接作为占位符的格式solc --link仍然支持但编译器已不再输出这种格式——这条备注说明它主要是为了链接更早版本编译器产出的旧二进制。为什么避免手工链接字节码文档对直接手工修改生成字节码里的库地址给了一条明确的 warning理由有两层手工链接不会更新合约元数据。元数据中保存了编译时指定的库列表而字节码里带有一个元数据哈希因此手工链接得到的二进制会随链接时机不同而不同——同一个合约、不同时间链接产出不同字节。文档给出的结论是应该在编译时就让编译器完成链接即solc的--libraries选项或 standard JSON 的libraries键。solc --link是编译器提供的规范化补救路径和用文本编辑器或脚本去 patch 字节码有本质区别本文主路径也按此取舍优先编译时链接--link仅作为已持有未链接二进制的补救。验证结果与边界链接是否完成可以用文档中的信息做两点核对看字节码输出中是否还有__$34位hex$__形式的子串。占位符存在即表示未链接文档明确Such bytecode is incomplete and should not be deployed此时不应部署看 JSON 输出对象上只要出现linkReferences它就是未链接对象。编译时通过--libraries/settings.libraries给全地址后输出的应是已完成链接的完整二进制。两个与链接直接相关的限制供对照环境时留意库自身在 Solidity 中的限制不能声明状态变量、不能继承或被继承、不能接收 Ether、不能被销毁见 Libraries。它只能部署一次到一个固定地址之后由调用方合约通过DELEGATECALL复用这正是要把该地址填进占位符的原因库的运行时代码与编译器报告的deployedBytecode不同部署代码会把运行时开头一个 20 字节零常量替换为实际部署地址用于区分CALL与DELEGATECALL调用模式即 call protection。也就是说链上实际存储的库代码和编译器输出不一致属预期行为不要拿链上代码去和deployedBytecode逐字节比对。完成链接后下一步就是把库合约本身部署到目标地址再部署已链接的主合约库的部署命令不在本文档范围内按你的部署工具操作即可。【免费下载链接】soliditySolidity, the Smart Contract Programming Language项目地址: https://gitcode.com/GitHub_Trending/so/solidity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考