Solidity合约异构调用Go合约失败
【问题分类】
- [√] bug
- P2P网络相关(包含libp2p,liquid)
- 链账户身份与权限相关(证书问题、public、多签投票问题)
- 核心交易引擎相关(交易池、DAG)
- 共识相关
- [√] 智能合约相关
- 存储相关
- SDK相关
- 长安链CMC工具
- 长安链管理台
- 长安链浏览器
- 长安链合约IDE
- 长安链web签名插件
- 跨链相关
- 轻节点相关
- 隐私计算相关
- 密码学相关
- 环境依赖
- 其他补充:
【问题描述】(请对问题进行描述,方便定位问题)
在长安链部署了CMNFA合约,CMC调用正常,Java调用Go合约正常,Solidity合约异构调用Go合约失败,报错信息:message: "parse cross vm param length failed"
【相关日志文件】(如果有报错日志请贴图,或者上传附件)
以下是solidity合约代码
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
// 导入 OpenZeppelin 的 Strings 库 (请确保路径正确)
import "@openzeppelin/contracts/utils/Strings.sol";
contract SolidityToGOMint {
// 在合约内部启用 Strings 库对 uint256 的方法
using Strings for uint256;
// 参数缓冲区大小不变,但修改变量名称以匹配 ChainMaker 文档示例
string[10] public params; // <--- 修改点: 将 paramsBuffer 改为 params
/**
* @notice 调用指定地址的 Go 合约的 Mint 方法,接收 uint256 tokenId
* @param goContractAddress 目标 Go 合约的地址
* @param to 接收 token 的地址 (对应 Go 的 to)
* @param tokenIdUint256 要铸造的 token 的 ID (uint256 类型)
* @param categoryName token 的类别名称 (对应 Go 的 categoryName)
* @param metadataString token 的元数据 (对应 Go 的 metadata []byte),需要预先编码为字符串
* @return success 指示低级调用是否成功 (EVM -> Go VM 通信层面)
* @return data 从 Go 合约返回的原始数据 (通常是 protogo.Response 的 bytes)
*/
function callGoMint(
address goContractAddress,
string calldata to,
uint256 tokenIdUint256,
string calldata categoryName,
string calldata metadataString
) public returns (bool success, bytes memory data) {
// 1. 填充参数缓冲区 (现在填充的是 params 状态变量)
params[0] = "CrossVMCall"; // 固定标识符
params[1] = "Mint"; // 目标 Go 方法名
// 参数 1: to
params[2] = "to";
params[3] = to;
// 参数 2: tokenId
params[4] = "tokenId";
params[5] = tokenIdUint256.toString(); // 将 uint256 转换为 string
// 参数 3: categoryName
params[6] = "categoryName";
params[7] = categoryName;
// 参数 4: metadata
params[8] = "metadata";
params[9] = metadataString; // 预编码的字符串
// 2. 发起异构调用
// 使用 goContractAddress.call("")
// EVM 会自动读取名为 'params' 的状态变量,并根据其内容构建发送给 Go VM 的实际参数。
(success, data) = goContractAddress.call("");
// 检查低级调用是否成功 (EVM 成功与 Go VM 通信)
require(success, "Heterogeneous call to Go Mint failed at EVM level");
// 'data' 将包含 Go 合约方法 (mintCore) 的完整 protogo.Response 编码。
// 你可以在链下解析这个 'data' 来查看 Go 合约的实际 ContractResult.code 和 message。
// 例如,如果 Go 合约返回 "only admin can mint tokens",这个信息会在 data 中。
return (success, data); // 返回低级调用结果和 Go 合约返回数据
}
}
传递给solidity合约的参数信息
尝试过将meta替换为普通的字符串也依然报错
Go合约代码为CMNFA合约,调用的函数如下
func (c *CMNFAContract) InvokeContract(method string) protogo.Response {
if len(method) == 0 {
return sdk.Error("method of param should not be empty")
}
switch method {
case "Standards":
return c.standardsCore()
case "SupportStandard":
return c.supportStandardCore()
case "Mint":
return c.mintCore()
func (c *CMNFAContract) mintCore() protogo.Response {
args := sdk.Instance.GetArgs()
to := string(args[paramTo])
tokenId := string(args[paramTokenId])
categoryName := string(args[paramCategoryName])
metadata := args[paramMetadata]
err := c.verifyToken(to, tokenId, categoryName)
if err != nil {
return sdk.Error(err.Error())
}
sender, err := sdk.Instance.Sender()
if err != nil {
return sdk.Error(fmt.Sprintf("get sender failed, err:%s", err))
}
admin, _, err := sdk.Instance.GetStateFromKeyWithExists(adminStoreKey)
if err != nil {
return sdk.Error(fmt.Sprintf("get admin failed, err:%s", err))
}
if sender != admin {
return sdk.Error("only admin can mint tokens")
}
err = c.Mint(to, tokenId, categoryName, metadata)
if err != nil {
return sdk.Error(err.Error())
}
//time.Sleep(time.Second * 2)
return sdk.Success([]byte("Mint success"))
}
【系统信息】(请填写系统信息,方便定位问题)
- chainmaker-go version * : [v2.3.5]
- OS & version * :
Linux version 5.15.0-124-generic (buildd@lcy02-amd64-092) (gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #134~20.04.1-Ubuntu SMP Tue Oct 1 15:27:33 UTC 2024
- docker镜像 version:
docker version
Client: Docker Engine - Community
Version: 28.0.2
API version: 1.48
Go version: go1.23.7
Git commit: 0442a73
Built: Wed Mar 19 14:36:56 2025
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 28.0.2
API version: 1.48 (minimum version 1.24)
Go version: go1.23.7
Git commit: bea4de2
Built: Wed Mar 19 14:36:56 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.26
GitCommit: 753481ec61c7c8955a23d6ff7bc8e4daed455734
runc:
Version: 1.2.5
GitCommit: v1.2.5-0-g59923ef
docker-init:
Version: 0.19.0
GitCommit: de40ad0
-
管理台 version:
- 如果是管理台的相关问题,请附带管理台版本,如果不是可忽略。
-
区块浏览器 version:
- 如果是浏览器的相关问题,请附带浏览器版本,如果不是可忽略。
-
合约IDE version:
- 如果是合约IDE的相关问题,请附带合约IDE版本,如果不是可忽略。
-
web签名插件 version:
- 如果是web签名插件的相关问题,请附带web签名插件版本,如果不是可忽略。
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information