abiObj 的 pack 函数打包[]string类型参数时,交易执行莫名失败
【问题分类】
- bug
- P2P网络相关(包含libp2p,liquid)
- 链账户身份与权限相关(证书问题、public、多签投票问题)
- 核心交易引擎相关(交易池、DAG)
- 共识相关
- 智能合约相关
- 存储相关
- SDK相关
- 长安链CMC工具
- 长安链管理台
- 长安链浏览器
- 长安链合约IDE
- 长安链web签名插件
- 跨链相关
- 轻节点相关
- 隐私计算相关
- 密码学相关
- 环境依赖
- 其他补充:
【问题描述】(请对问题进行描述,方便定位问题)
具体的现象,操作步骤,前置条件等,尽可能描述清楚,有截图说明更佳
(代码那块儿的格式我调了很久也调不好,代码块这个插件也不知道怎么识别的...)
具体的问题: 似乎 chainmaker 对部署在 evm 的 solidity 合约支持有欠缺,具体表现为当合约接受一个string[]类型的参数时,在golang编程环境下调用abiObj.Pack函数时,传入了[]string类型的变量,会导致交易执行失败,并且没有报错信息,按道理来说不是就应该传这个类型的变量嘛 后来尝试把合约和Pack函数中的string[]都换成了string,就一切正常了,不知道是不是我传参数或者调用函数的姿势有问题?
操作流程如下:
首先准备一个solidity合约
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Test { string[] public idList;
function set(string[] calldata _idList) public {
idList = _idList;
}
function get() public view returns (string[] memory) {
return idList;
}
}
- 通过官方的 docker 镜像 chainmakerofficial/chainmaker-solidity-contract:2.0.0 生成 bin 和 abi 等文件
- chainmaker-go 用的是 v2.3.5 版本, chainmaker-cryptogen 也是 v2.3.5版本
- 走正常 prepare_pk.sh -> build_release.sh -> cluster_quick_start.sh 三件套启动链
- 以pk模式启动链,通过以下函数进行合约部署和合约调用
- 代码中涉及到的 GetEndorsersWithAuthType, InvokeUserContractWithResult 等函数都是用的官方example里的实现,就不额外贴了
package oracle
import ( "chainmaker.org/chainmaker/common/v2/evmutils/abi" "chainmaker.org/chainmaker/pb-go/v2/common" sdk "chainmaker.org/chainmaker/sdk-go/v2" "chainmaker.org/chainmaker/sdk-go/v2/utils" "encoding/hex" "io/ioutil" "log" "os" "strings" "testing" )
const ( ContractName = "MyTest" contractVersion = "1.0" abiPath = "./contract/oracle/solidity/MyTest.abi" byteCodePath = "./contract/oracle/solidity/MyTest.bin" )
var usernames = []string{"org1admin1", "org2admin1", "org3admin1", "org4admin1"}
var client *sdk.ChainClient
func TestMain(m *testing.M) { var err error wd, _ := os.Getwd() log.Printf("wd: %s", wd) os.Chdir("../../") client, err = sdk.NewChainClient( sdk.WithConfPath("./chain/sdk_config_pk.yml"), ) if err != nil { log.Fatalf("Failed to initialize client: %v", err) }
code := m.Run()
os.Exit(code)
}
func TestDepoly(t *testing.T) { payload, err := client.CreateContractCreatePayload(ContractName, contractVersion, byteCodePath, common.RuntimeType_EVM, nil) if err != nil { log.Printf("CreateContractCreatePayload err:%+v", err) return }
endorsers, err := chain.GetEndorsersWithAuthType(client.GetHashType(),
client.GetAuthType(), payload, usernames...)
if err != nil {
log.Printf("GetEndorsersWithAuthType failed, err:%v\n", err)
return
}
resp, err := client.SendContractManageRequest(payload, endorsers, constdef.ContractTimeOut, true)
if err != nil {
log.Printf("SendContractManageRequest err:%+v", err)
return
}
err = utils.CheckProposalRequestResp(resp, true)
if err != nil {
log.Printf("CheckProposalRequestResp err:%+v", err)
return
}
}
func TestSet(t *testing.T) { //读取abi文件 abiBytes, _ := ioutil.ReadFile(abiPath) //构建abi对象 abiObj, _ := abi.JSON(strings.NewReader(string(abiBytes))) //计算calldata callData, err := abiObj.Pack("set", []string{"aa"}) if err != nil {
return
}
dataString := hex.EncodeToString(callData)
kvs := []*common.KeyValuePair{
{
Key: "data",
Value: []byte(dataString),
},
}
_, err = chain.InvokeUserContractWithResult(client, ContractName, "set", "", kvs, true)
if err != nil {
log.Printf("Set InvokeUserContractWithResult err:%+v", err)
return
}
}
func TestGet(t *testing.T) { //读取abi文件 abiBytes, _ := ioutil.ReadFile(abiPath) //构建abi对象 abiObj, _ := abi.JSON(strings.NewReader(string(abiBytes))) //计算calldata callData, err := abiObj.Pack("get") if err != nil { return } dataString := hex.EncodeToString(callData)
kvs := []*common.KeyValuePair{
{
Key: "data",
Value: []byte(dataString),
},
}
resBytes, err := chain.InvokeUserContractWithResult(client, ContractName, "get", "", kvs, true)
if err != nil {
log.Printf("Get InvokeUserContractWithResult err:%+v", err)
return
}
addr, err := abiObj.Unpack("get", resBytes)
if err != nil {
return
}
log.Println("res: " + addr[0].(string))
}
最后运行TestSet单测得到报错,只有code:4,没有msg
=== RUN TestSet 2025/02/14 18:38:01 Set InvokeUserContractWithResult err:invoke contract failed, [code:4]/[msg:] --- PASS: TestSet (0.51s)
类似的可以发现,如果将合约中 Get 方法的返回值也设置成string[] memory,会发现无法正确解析addr ,个人猜测可能是同样的原因,就不额外补充了
【相关日志文件】(如果有报错日志请贴图,或者上传附件)
chainmaker-go 的 log/system.log & bin/panic.log file *
节点的 system.log 报错如下
2025-02-14 18:26:56.101 [ERROR] [Vm] [31;1m@chain1[0m v2@v2.3.6/runtime.go:485 revert instruction encountered in contract [MyTest] execution, tx: [18240c3de744c038caeeb764c3dcd5660afe3e91420047d7bc39f0517b42e2a7], error: [] 2025-02-14 18:26:56.101 [ERROR] [Vm] [31;1m@chain1[0m v2@v2.3.6/runtime.go:494 error encountered in contract [MyTest] execution, tx: [18240c3de744c038caeeb764c3dcd5660afe3e91420047d7bc39f0517b42e2a7], error: [] 2025-02-14 18:26:56.101 [ERROR] [Vm] [31;1m@chain1[0m v2@v2.3.6/runtime.go:398 evm runtime execute contract failed, tx id:18240c3de744c038caeeb764c3dcd5660afe3e91420047d7bc39f0517b42e2a7, pc count:257, time used:128, error:execution reverted 2025-02-14 18:26:56.101 [ERROR] [Vm] [31;1m@chain1[0m v2@v2.3.6/runtime.go:538 failed to execute evm contract, execution reverted 2025-02-14 18:26:56.103 [ERROR] [Core] [31;1m@chain1[0m scheduler/scheduler.go:707 failed to run vm for tx id:18240c3de744c038caeeb764c3dcd5660afe3e91420047d7bc39f0517b42e2a7,contractName:MyTest, tx result:code:CONTRACT_FAIL contract_result:<code:1 message:"failed to execute evm contract, execution reverted" gas_used:1 > , error:failed to execute evm contract, execution reverted
sdk日志报错如下,可以发现也没啥信息量
2025-02-14 18:26:47.856 [DEBUG] [SDK] v2@v2.3.6/sdk_user_contract.go:170 [SDK] begin to INVOKE contract, [contractName:MyTest]/[method:get]/[txId:]/[params:[key:"data" value:"6d4ce63c" ]] 2025-02-14 18:26:47.859 [DEBUG] [SDK] v2@v2.3.6/sdk_common.go:57 [SDK] begin to QUERY system contract, [method:GET_TX_BY_TX_ID]/[txId:18240c3bfce4e870caf46e3a2d8a8c445afa03e635d64f66a59f0e43dbe22fbf] 2025-02-14 18:26:48.362 [DEBUG] [SDK] v2@v2.3.6/sdk_common.go:57 [SDK] begin to QUERY system contract, [method:GET_TX_BY_TX_ID]/[txId:18240c3bfce4e870caf46e3a2d8a8c445afa03e635d64f66a59f0e43dbe22fbf] 2025-02-14 18:26:56.083 [DEBUG] [SDK] v2@v2.3.6/sdk_user_contract.go:170 [SDK] begin to INVOKE contract, [contractName:MyTest]/[method:set]/[txId:]/[params:[key:"data" value:"52e66db80000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000026161000000000000000000000000000000000000000000000000000000000000" ]] 2025-02-14 18:26:56.086 [DEBUG] [SDK] v2@v2.3.6/sdk_common.go:57 [SDK] begin to QUERY system contract, [method:GET_TX_BY_TX_ID]/[txId:18240c3de744c038caeeb764c3dcd5660afe3e91420047d7bc39f0517b42e2a7] 2025-02-14 18:26:56.589 [DEBUG] [SDK] v2@v2.3.6/sdk_common.go:57 [SDK] begin to QUERY system contract, [method:GET_TX_BY_TX_ID]/[txId:18240c3de744c038caeeb764c3dcd5660afe3e91420047d7bc39f0517b42e2a7] 2025-02-14 18:27:22.064 [DEBUG] [SDK] v2@v2.3.6/sdk_user_contract.go:170 [SDK] begin to INVOKE contract, [contractName:MyTest]/[method:set]/[txId:]/[params:[key:"data" value:"52e66db80000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000026161000000000000000000000000000000000000000000000000000000000000" ]] 2025-02-14 18:27:22.068 [DEBUG] [SDK] v2@v2.3.6/sdk_common.go:57 [SDK] begin to QUERY system contract, [method:GET_TX_BY_TX_ID]/[txId:18240c43f3e20868ca64b8b704270fb90eb158b0bb6041afaacf08358c5ae5cf] 2025-02-14 18:27:22.570 [DEBUG] [SDK] v2@v2.3.6/sdk_common.go:57 [SDK] begin to QUERY system contract, [method:GET_TX_BY_TX_ID]/[txId:18240c43f3e20868ca64b8b704270fb90eb158b0bb6041afaacf08358c5ae5cf]
【系统信息】(请填写系统信息,方便定位问题)
- chainmaker-go version * : [v2.3.5]
- OS & version * : Mac m1芯片, go1.18.2
- docker镜像 version: 编译合约用的chainmakerofficial/chainmaker-solidity-contract:2.0.0镜像,其余都是走的脚本部署
-
管理台 version:
- 如果是管理台的相关问题,请附带管理台版本,如果不是可忽略。
-
区块浏览器 version:
- 如果是浏览器的相关问题,请附带浏览器版本,如果不是可忽略。
-
合约IDE version:
- 如果是合约IDE的相关问题,请附带合约IDE版本,如果不是可忽略。
-
web签名插件 version:
- 如果是web签名插件的相关问题,请附带web签名插件版本,如果不是可忽略。