在evm中,使用solidity合约调用其他solidity合约返回值问题
【问题分类】
- [] bug
- P2P网络相关(包含libp2p,liquid)
- 链账户身份与权限相关(证书问题、public、多签投票问题)
- 核心交易引擎相关(交易池、DAG)
- 共识相关
- 智能合约相关
- 存储相关
- SDK相关
- 长安链CMC工具
- 长安链管理台
- 长安链浏览器
- 长安链合约IDE
- 长安链web签名插件
- 跨链相关
- 轻节点相关
- 隐私计算相关
- 密码学相关
- 环境依赖
- 其他补充:
【问题描述】(请对问题进行描述,方便定位问题)
在issue-789中,使用docker部署,合约内部调用其他合约会报jump out of range异常,考虑可能是版本问题后,采用脚本直接部署,chainmaker分支代码为2.3.2,使用当前分支可以直接调用跨链,但是使用过程中有2个问题。 其一:智能合约地址如果是以0x开头的哈希字符串,自己本身调用是没有问题的,如果作为方法参数,以0x开头会出现contract name not found的异常,如果去掉0x则不会出现这个问题。 其二:返回值中含有特殊字符,无法正常解析返回参数
具体的现象,操作步骤,前置条件等,尽可能描述清楚,有截图说明更佳
pragma solidity >=0.5.0 <0.6.0;
contract HelloWorld {
string name = "HelloWorld!";
constructor(string memory n) public {
name = n;
}
function get() public view returns (string memory) {
return name;
}
function set(string memory n) public {
name = n;
}
function get1(string memory s) public pure returns (string memory) {
return s;
}
function get2(string memory s1, string memory s2) public pure returns (string memory) {
return string(abi.encodePacked(s1, s2));
}
}
pragma solidity >=0.4.22 <0.6.0;
contract Test {
function callOtherContract(address contractAddress,string memory method,string memory n)public returns(bytes memory result)
{
bool success;
(success, result) = contractAddress.call( abi.encodeWithSignature(method, n));
return result;
}
function get() public view returns(string memory){
return "1111";
}
}
###部署hellword合约
public static String deployHelloWorld(ChainClient chainClient) throws Exception {
ResultOuterClass.TxResponse responseInfo = null;
//这里的合约地址和evm有点差异,不能以0x开头,否则在下文作为参数调用时会提示contract name not found
String contractAddress = CryptoUtils.nameToAddrStr("HelloWorld", ChainConfigOuterClass.AddrType.ETHEREUM);
try {
byte[] byteCode = FileUtils.getResourceFileBytes("HelloWorld.bin");
String deployFunction = FunctionEncoder.encodeConstructor(Arrays.asList(new Utf8String("HelloWorld2023")));
Map<String, byte[]> queryParamMap = new HashMap<>();
queryParamMap.put("data", deployFunction.getBytes());
System.out.println("hello word contract address:" + contractAddress);
Request.Payload payload = chainClient.createContractCreatePayload(contractAddress, "1", byteCode,
ContractOuterClass.RuntimeType.EVM, null);
Request.EndorsementEntry[] endorsementEntries = SdkUtils
.getEndorsers(payload, new User[]{chainClient.getClientUser()});
responseInfo = chainClient.sendContractManageRequest(payload, endorsementEntries, 10000, 10000);
System.out.println("response:" + responseInfo.toString());
} catch (Exception e) {
e.printStackTrace();
}
return contractAddress;
}
###部署test合约
public static void deployTest(ChainClient chainClient,String contractAddress) throws Exception {
ResultOuterClass.TxResponse responseInfo = null;
String testAddress = CryptoUtils.nameToAddrStr("Test", ChainConfigOuterClass.AddrType.ETHEREUM);
try {
byte[] byteCode = FileUtils.getResourceFileBytes("Test.bin");
Request.Payload payload = chainClient.createContractCreatePayload(testAddress, "1", byteCode,
ContractOuterClass.RuntimeType.EVM, null);
Request.EndorsementEntry[] endorsementEntries = SdkUtils
.getEndorsers(payload, new User[]{chainClient.getClientUser()});
responseInfo = chainClient.sendContractManageRequest(payload, endorsementEntries, 10000, 10000);
System.out.println("response:" + responseInfo.toString());
} catch (Exception e) {
e.printStackTrace();
}
callOtherContract(chainClient,contractAddress,testAddress);
}
###test调用helloworld合约
private static void callOtherContract(ChainClient chainClient, String contractAddress, String testAddress) throws ChainMakerCryptoSuiteException, ChainClientException {
Function callFunction = new Function("callOtherContract", Arrays.asList(new Address(contractAddress),new Utf8String("get1(string)"),new Utf8String("12333")),
Arrays.<TypeReference<?>>asList(new TypeReference<DynamicBytes>() {
}));
String callMethod = FunctionEncoder.encode(callFunction);
HashMap<String, byte[]> callParams = new HashMap<>();
String callMethodId = callMethod.substring(0, 10);
callParams.put("data", callMethod.getBytes());
ResultOuterClass.TxResponse callResult = chainClient.invokeContract(testAddress, callMethodId, null, callParams, 3000, 3000);
byte[] byteArray = callResult.getContractResult().getResult().toByteArray();
String callHex = Hex.toHexString(byteArray);
List<Type> decode = FunctionReturnDecoder.decode(callHex, callFunction.getOutputParameters());
DynamicBytes type = (DynamicBytes)decode.get(0);
System.out.println("before:"+new String(type.getValue()));
boolean flag32 = false;
boolean flag96 = false;
for (int i = 0; i < byteArray.length; i++) {
if (flag32 && flag96) {
break;
}
if (byteArray[i] == 32 && !flag32) {
byteArray[i] = 0;
flag32 = true;
}
if (byteArray[i] == 96 && !flag96) {
byteArray[i] = 0;
flag96 = true;
}
}
System.out.println("after:"+new String(byteArray).replaceAll("\\p{C}", "").trim());
}
如果返回结果不特殊处理,是没有办法正确解析出来,目前只有合约调合约会出现这种情况
【相关日志文件】(如果有报错日志请贴图,或者上传附件)
chainmaker-go 的 log/system.log & bin/panic.log file *
SDK 的 sdk.log file
【系统信息】(请填写系统信息,方便定位问题)
- chainmaker-go version * : [v2.3.2]
- OS & version * :
- docker镜像 version:
-
管理台 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