使用Go-ethereum解码以太坊交易输入数据遇RLP错误求助
问题根源
以太坊智能合约交易的输入数据(前4字节为函数选择器,剩余部分为函数参数)采用ABI编码,而非你使用的RLP编码。RLP仅用于以太坊底层数据(如交易本体、区块头)的序列化,不适用于合约函数参数解码,这是导致你遇到rlp: expected input list for []main.SwapFunction错误的核心原因。
解决方案
使用go-ethereum的accounts/abi包进行ABI解码,步骤如下:
1. 获取目标合约的ABI
从交易对应的合约页面导出ABI(可通过交易详情页的合约地址跳转获取),将其保存为字符串或本地文件。
2. 调整代码逻辑
替换原有的RLP解码逻辑,改用ABI解码。以下是修改后的完整代码:
package main import ( "context" "encoding/json" "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) // 保持原结构体定义不变,需与ABI中的函数参数结构匹配 type SwapDescription struct { SrcToken common.Address DstToken common.Address SrcReceiver common.Address DstReceiver common.Address Amount *big.Int MinReturnAmount *big.Int GuaranteedAmount *big.Int Flags *big.Int Referrer common.Address Permit []byte } type CallDescription struct { TargetWithMandatory *big.Int GasLimit *big.Int Value *big.Int Data []byte } type SwapFunction struct { Caller common.Address Desc SwapDescription Calls []CallDescription } func main() { // 连接以太坊网络 client, err := ethclient.Dial("https://eth-mainnet.alchemyapi.io/jsonrpc/MY-API-KEY") if err != nil { fmt.Println("连接以太坊网络失败:", err) return } // 交易哈希 txHash := "0xd918b14504b82d4c5334a751e0439826e682a57c6813f16a707801f89f589b90" hash := common.HexToHash(txHash) tx, isPending, err := client.TransactionByHash(context.Background(), hash) if err != nil { fmt.Println("获取交易失败:", err) return } if isPending { fmt.Println("交易处于pending状态") return } input := tx.Data() if len(input) < 4 { fmt.Println("输入数据长度不足") return } // 1. 填入目标合约的ABI字符串(从合约页面复制) abiStr := `[{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"struct ISwapRouter.SwapDescription","name":"desc","type":"tuple"},{"internalType":"struct ISwapRouter.CallDescription[]","name":"calls","type":"tuple[]"}],"name":"swap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"}]` // 2. 解析ABI contractABI, err := abi.JSON(json.RawMessage(abiStr)) if err != nil { fmt.Println("解析ABI失败:", err) return } // 3. 解码函数参数 var decodedData SwapFunction err = contractABI.UnpackIntoInterface(&decodedData, "swap", input[4:]) if err != nil { fmt.Println("解码参数失败:", err) return } // 输出解码结果 fmt.Printf("解码后的Caller: %s\n", decodedData.Caller.Hex()) fmt.Printf("SrcToken: %s\n", decodedData.Desc.SrcToken.Hex()) fmt.Printf("Amount: %s\n", decodedData.Desc.Amount.String()) // 可按需输出其他字段 }
关键说明
- 确保
abiStr中的函数定义与交易调用的函数完全匹配(包括参数名称、类型、顺序),否则解码会失败。 - 如果合约ABI包含更多函数,只需保留目标函数
swap的ABI片段即可,无需完整ABI。 - ABI解码会自动处理以太坊数据类型与Go语言类型的映射(如
address对应common.Address,uint256对应*big.Int)。
内容的提问来源于stack exchange,提问作者chris
相关产品推荐
相关产品推荐

