go-ethereum是否支持无需ABI的输入数据编解码操作
go-ethereum 轻量ABI编解码实现方案
go-ethereum 原生提供了和 web3.js 对等的编解码能力,无需加载完整合约ABI文件,仅需指定参数类型即可完成以太坊交易输入数据的编码、解码操作,相关能力封装在官方标准包 accounts/abi 中。
1. 参数解码(对应web3.js decodeParameters)
你只需要按参数顺序传入类型列表、待解码的十六进制数据,即可完成解码,不需要提前导入完整合约ABI。
示例代码(和web3.js示例使用完全相同的测试数据):
package main import ( "fmt" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "math/big" ) func main() { // 按顺序定义参数类型,和web3.js传入的类型数组一一对应 paramTypes := []string{"uint256", "uint256", "address[]", "address", "uint256"} args := make(abi.Arguments, len(paramTypes)) for idx, typeStr := range paramTypes { t, err := abi.NewType(typeStr, "", nil) if err != nil { panic(err) } args[idx] = abi.Argument{Type: t} } // 待解码原始数据(可不带0x前缀) rawHex := "000000000000000000000000000000000000000000000001885c663d0035bce200000000000000000000000000000000000000000000000000f5666f7fdaa62600000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000c0be713b48822271b362e9fac00479f5134172e80000000000000000000000000000000000000000000000000000000060e93fa900000000000000000000000000000000000000000000000000000000000000020000000000000000000000009813037ee2218799597d83d4a5b6f3b6778218d9000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" inputBytes := common.Hex2Bytes(rawHex) // 执行解码 decodeRes := make(map[string]interface{}) err := args.UnpackIntoMap(decodeRes, inputBytes) if err != nil { panic(err) } // 输出结果和web3.js完全一致: // decodeRes["0"] = 28272584972907691234(*big.Int类型) // decodeRes["1"] = 69073998366549542(*big.Int类型) // decodeRes["2"] = 长度为2的地址切片 // decodeRes["3"] = 0xc0Be713B48822271b362e9Fac00479f5134172e8(common.Address类型) // decodeRes["4"] = 1625898921(*big.Int类型) fmt.Printf("%+v\n", decodeRes) }
2. 函数调用编码(对应web3.js encodeFunctionCall)
仅需传入函数名、参数类型列表、待编码参数值,即可生成符合ABI规范的合约调用数据,无需完整ABI。
示例代码(和web3.js示例使用完全相同的测试参数):
package main import ( "fmt" "github.com/ethereum/go-ethereum/accounts/abi" "math/big" ) func main() { // 定义函数基础信息、输入参数类型 methodName := "myMethod" inputParamTypes := []string{"uint256", "string"} inputArgs := make(abi.Arguments, len(inputParamTypes)) for idx, typeStr := range inputParamTypes { t, err := abi.NewType(typeStr, "", nil) if err != nil { panic(err) } inputArgs[idx] = abi.Argument{Type: t} } method := abi.NewMethod(methodName, methodName, abi.Function, "", false, false, inputArgs, abi.Arguments{}) // 传入待编码参数值 params := []interface{}{ big.NewInt(2345675643), "Hello!%", } // 打包参数、拼接4字节函数选择器 packedParams, err := method.Inputs.Pack(params...) if err != nil { panic(err) } fullCallData := append(method.ID, packedParams...) // 输出结果和web3.js完全一致:0x24ee0097000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000 fmt.Printf("0x%x\n", fullCallData) }
使用说明
- 所有Solidity支持的类型(动态数组、结构体、嵌套类型等)都可以通过
abi.NewType直接解析,不需要依赖完整ABI JSON文件 - 解码返回值的类型映射规则:整数统一为
*big.Int、地址为common.Address、动态字节为[]byte、字符串为string、数组/定长数组对应Go切片/数组 - 如果解码带函数选择器的完整调用数据,需要先截掉前4字节的选择器部分,再传入解码方法
内容的提问来源于stack exchange,提问作者Moon soon
相关产品推荐
相关产品推荐

