ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入 fuels-rs 的 fuels-abi-cli:Sway 函数调用的 ABI 编码与解码实战

深入 fuels-rs 的 fuels-abi-cli:Sway 函数调用的 ABI 编码与解码实战 深入 fuels-rs 的 fuels-abi-cliSway 函数调用的 ABI 编码与解码实战【免费下载链接】fuels-rsFuel Network Rust SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-rs在 Fuel 生态中智能合约之间以及客户端与合约之间的每一次调用本质上都是一串符合既定 ABIApplication Binary Interface规范的字节数据调用方需要把方法名与参数编码成字节流结果方或分析方则需要把返回的字节流还原成可读的类型值。fuels-abi-cli正是这样一个面向fuels-rsFuel Network 的 Rust SDK开发者的命令行小工具编码 Sway 函数调用、解码其输出同时支持把一份完整的 JSON ABI 文件作为输入针对其中声明的某个函数生成可直接用于调用/调试的字节数据。阅读本文后你将能独立完成函数参数的字面量编码、基于 JSON ABI 文件的函数级编码含结构体、数组等复合类型、以及把返回数据解码回可读类型值并理解字节流中函数选择器function selector的布局规则。文档原文位于 docs/src/cli/fuels-abi-cli.md它隶属于 docs/src/cli/index.md 所描述的「fuels-rs 各工作区概览」章节。需要说明的是从当前仓库根目录的工作区清单 Cargo.toml 看独立二进制fuels-abi-clicrate 已不再是members之一本文按文档中的用法讲解其命令语义而它背后的编解码能力仍完整保留在fuels-core/fuels-code-gen的 codec 模块中本文会同步给出对应源码位置供对照深挖。一、工具定位一个「FuelVM ABI 编解码器」CLI 帮助信息中即自称FuelVM ABI coder。它的职责可以拆成两条主线编码encode把 Sway 函数调用翻译成十六进制字节串。既可以只对一组参数编码也可以结合 JSON ABI 文件对整个函数调用编码此时会额外输出函数选择器前缀。解码decode把 ABI 返回的字节串翻译回可读的类型值。同样支持「纯参数」与「函数输出」两种粒度。此外它还保留了一个codegen子命令用于输出 Rust 类型文件——这呼应了 SDK 中abigen宏「根据 ABI 生成 Rust 绑定类型」的职责参见 docs/src/abigen/the-json-abi-file.md。完整的顶层帮助信息如下sway-abi-cli 0.1.0 FuelVM ABI coder USAGE: sway-abi-cli SUBCOMMAND FLAGS: -h, --help Prints help information -V, --version Prints version information SUBCOMMANDS: codegen Output Rust types file decode Decode ABI call result encode Encode ABI call help Prints this message or the help of the given subcommand(s)在 fuels-rs 的历史工作区语境下一般通过cargo run -- 子命令 ...的形式在 crate 内运行该程序文档中的示例均采用该写法。二、编码调用encode有两种工作模式只对给定的参数列表编码encode params基于一份JSON ABI 文件对其中声明的某个函数调用做整体编码encode function此时结果会在参数数据之前补上函数选择器。2.1 只编码参数encode params$ cargo run -- encode params -v bool true 0000000000000001$ cargo run -- encode params -v bool true -v u32 42 -v u32 100 0000000000000001000000000000002a0000000000000064规则文档明确强调每编码一个参数都必须传一个-v标志后跟该参数的类型与取值格式为-v type_1 value_1 -v type_2 value_2 ... -v type_n value_n从输出字节串可以直观看出 Fuel ABI 的定长 word 对齐惯例bool true被编码为 8 字节一个 word0000000000000001u32 42十六进制0x2a同样占满一个 word...2au32 1000x64编码为...64。三个 word 首尾相接即是最终结果参数按-v出现顺序依次排列。这与fuels-core中 ABIEncoder 把每个Token顺序写入编码缓冲区的行为一致其入口encode位于该文件第 43 行。2.2 编码一个函数调用encode function「函数级」编码的前置条件是一份描述该函数签名的 JSON ABI 文件。例如simple.json[ { type:function, inputs:[ { name:arg, type:u32 } ], name:takes_u32_returns_bool, outputs:[ { name:, type:bool } ] } ]该文件的字段语义与 SDK 主文档对 JSON ABI 的描述完全一致顶层是函数描述数组每个条目包含type如function、name、inputs、outputs其中inputs/outputs的元素用nametype声明类型更多结构见 the-json-abi-file.md。随后用函数名选择 ABI 中的目标函数并通过-p传入实参$ cargo run -- encode function examples/simple.json takes_u32_returns_bool -p 4 000000006355e6ee0000000000000004encode function的取值采用类 Sway/JSON 字面量语法而非逐参数-v这里传入的-p 4对应函数唯一的u32输入。函数选择器的布局文档明确说明输出字节流中的第一个 word前 8 字节专门留给函数选择器而选择器本身落在该 word 的最后 4 字节它是函数签名的 256 位哈希SHA-256经截取得到的标识。以上例剖析00000000 6355e6ee | 0000000000000004 └─ selector word ┘ └── u32 arg 4 ──┘ 高 4 字节为 0 低 4 字节 签名哈希片段 6355e6ee也就是说6355e6ee正是函数takes_u32_returns_bool签名的哈希标识调用方借助它才能让链上或解析端定位到具体方法。2.3 复合类型的参数编码数组与嵌套结构体当参数是数组时类型串使用u16[3]这样的语法声明长度。array.json[ { type:function, inputs:[ { name:arg, type:u16[3] } ], name:takes_array, outputs:[ { name:, type:u16[2] } ] } ]编码时实参写成数组字面量注意 shell 引号包裹$ cargo run -- encode function examples/array.json takes_array -p [1,2] 00000000f0b8786400000000000000010000000000000002可以观察到数组的两个元素1、2各自被扩展成独立的 8 字节 word且长度声明u16[3]与实参[1,2]的元素个数并不要求严格一致——编码按实际传入值逐个写出f0b87864为该函数的哈希选择器。结构体、枚举等复合类型需要借助components字段在 JSON ABI 中递归声明其内部成员。看一个嵌套结构体nested_struct.json[ { type:contract, inputs:[ { name:MyNestedStruct, type:struct, components:[ { name:x, type:u16 }, { name:y, type:struct, components:[ { name:a, type:bool }, { name:b, type:u8[2] } ] } ] } ], name:takes_nested_struct, outputs:[ ] } ]它的编码命令与实参语法如下$ cargo run -- encode function examples/nested_struct.json takes_nested_struct -p (10, (true, [1,2])) 00000000e8a04d9c000000000000000a000000000000000100000000000000010000000000000002拆解这段输出即可验证递归展开 word 对齐规则00000000 e8a04d9c 函数选择器 word哈希片段 e8a04d9c 000000000000000a 字段 x: u16 10 0000000000000001 字段 y.a: bool true 0000000000000001 字段 y.b[0]: u8 1 0000000000000002 字段 y.b[1]: u8 2注意结构体是按成员顺序「扁平化」拼接的内层u8数组元素同样各自独占 8 字节这正是 Fuel ABI 强调的按 word 定长对齐的编码哲学。三、解码调用解码与编码对称均提供「只解码参数」与「解码函数输出」两种模式。区别在于decode的参数类型用-t声明-t type可多次出现并以十六进制字节串作为待解码的数据本体。3.1 只解码参数decode params把上一节encode params的结果原样喂回解码器$ cargo run -- decode params -t bool -t u32 -t u32 0000000000000001000000000000002a0000000000000064 Bool(true) U32(42) U32(100)每个类型对应一行「类型名(值)」形式的可读输出类型按-t出现顺序与数据中的 word 一一对应。这种「把 Token 转成带类型前缀的可读字符串」的表达能力在fuels-core中对应着 decode_as_debug_str.rs 的decode_as_debug_str函数第 19 行起它依据ParamType与Token的配对输出字符串对Bool/U8/U32… 各基础类型逐一映射并支持 Tuple 输出(a, b)、Array/Vector 输出[e1, e2]、Struct 输出Name { field: ... }、Enum 输出Variant(...)等递归格式。3.2 解码函数输出decode function当需要还原某次真实合约调用的返回值时结合 JSON ABI 声明函数签名即可让解码器知道返回类型的布局$ cargo run -- decode function examples/simple.json takes_u32_returns_bool 0000000000000001 Bool(true)decode function的三段参数为ABI文件 函数名 数据。对照simple.json中takes_u32_returns_bool的outputs声明bool解码器把0000000000000001解读为布尔真值输出Bool(true)。四、从源码理解这套能力的「底座」虽然fuels-abi-cli是独立的小工具但它所展示的编码/解码/哈希选择器逻辑与 fuels-rs 主干代码中的 codec 层是一脉相承的编码侧ABIEncoder 通过encode把参数Token序列编码成字节流宏形式的便捷入口calldata!与 re-export 的encode_fn_selector被集中暴露在 function_selector.rs。选择器生成fuels-code-gen/src/utils.rs 中的encode_fn_selector第 3–8 行给出了仓库内函数选择器字节串的生成实现先把函数名转为字节再在前面拼接8 字节大端长度前缀len.to_be_bytes() 名称字节供后续调用描述与脚本生成使用。可见「选择器」在 fuels-rs 代码生成链路中承担的是把函数名稳定地带入调用字节的作用与 ABI 文档所描述的哈希选择器共同构成了函数定位的两层机制。解码侧ABIDecoder 负责把返回字节还原为类型化Token而「打印成人类可读字符串」的职责则由decode_as_debug_str独立承担其单元测试覆盖了 bool/u8/u16/u32/u64/u128/u256、Bits256、Bytes、RawSlice、定长与动态字符串、Tuple、数组、Option、Result等类型见 decode_as_debug_str.rs 测试段。ABI 数据来源CLI 读取的 JSON ABI 正是 Fuel 编译器forc为合约/脚本产出的*-abi.jsonSDK 侧对这类文件的字段语义有专门讲解详见 docs/src/abigen/the-json-abi-file.md仓库中亦可找到一份真实的 ABI JSON 样例 examples/rust_bindings/src/abi.json。五、快速上手小结操作命令形态关键点编码纯参数encode params -v type value ...每参数一个-v输出按 8 字节 word 对齐拼接编码函数调用encode function abi.json fn -p value第一个 word 预留函数选择器哈希片段落在低 4 字节解码纯参数decode params -t type ... hex-t声明类型末尾为字节串输出Type(value)解码函数输出decode function abi.json fn hex依outputs声明还原返回类型生成 Rust 绑定codegen由 ABI 产出 Rust 类型文件编写/验证 ABI 字节数据时可先用encode生成样本再用decode回读比对若结果与预期不一致优先检查「word 是否 8 字节对齐」「结构体成员顺序」「函数选择器是否占用了首 word」这三处——这正是 ABI 编解码最容易出错的细节。【免费下载链接】fuels-rsFuel Network Rust SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-rs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表