Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Sign in
issue
issue
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 25
    • Issues 25
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Commits
  • Issue Boards
Collapse sidebar

新注册的用户请输入邮箱并保存,随后登录邮箱激活账号。后续可直接使用邮箱登录!

  • chainmaker
  • issueissue
  • Issues
  • #844

Closed
Open
Opened Sep 26, 2023 by shi zhenxing@szx1874058817

链上数据查询请求解析不到原数据

mobileV2.sol

以上是solidity合约源码

上链合约方法是addOfflineData和setOfflineData

以下是我自己的java代码请求上链,是可以成功上链数据的

        HttpUtil httpUtil = new HttpUtil();
        ResponseEntity<String> response = httpUtil.sendPostRequestFileAndGetResponse(environment.getProperty("ipfs_path"), basePath + fileName);
        System.out.println("ipfs上传数据返回的值是:"+response);
        if (response.getStatusCode().is2xxSuccessful()){
            try {
                String body = response.getBody();
                JSONObject resultJson = JSONObject.parseObject(body);
                //ipfs中文件存储的hash
                String fileHash = (String) resultJson.get("Hash");

                Map<String, byte[]> firstParams = new HashMap<>();
                //构建参数集合
                List<Type> firstOfflineData = new ArrayList<>();
                firstOfflineData.add(new Utf8String(IdGenerate.generateStrID()));
                firstOfflineData.add(new Utf8String(orgName));
                firstOfflineData.add(new Utf8String(sysUser.getUserId().toString()));
                firstOfflineData.add(new Utf8String(sysUser.getUserName()));
                Date date = new Date();
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                String nowDate = format.format(date);
                firstOfflineData.add(new Utf8String(nowDate));
                firstOfflineData.add(new Utf8String("0"));
                //调用第一个合约
                ContractRequets contractRequets = new ContractRequets(chainClientConfig);
                ResultOuterClass.TxResponse responseInfo = contractRequets.requestContract(sysUser, firstParams, firstOfflineData,CertConstants.PUSH_DATA_CHAIN_CONTRACT_NAME,CertConstants.PUSTH_DATA_CHAIN_METHOD_NAME_ADD);
                //上个合约地址
                System.out.println("第一次请求合约执行后返回值是:"+ Numeric.toBigInt(responseInfo.getContractResult().getResult().toByteArray()));

                //调用第二个合约
                Map<String, byte[]> secondParams = new HashMap<>();
                List<Type> secondOfflineData = new ArrayList<>();
                secondOfflineData.add(new Utf8String(dbName));
                secondOfflineData.add(new Utf8String(tableName));
                secondOfflineData.add(new Utf8String(createSql));
                secondOfflineData.add(new Utf8String(metadata.get(1)));
                secondOfflineData.add(new Utf8String("1"));
                secondOfflineData.add(new Utf8String(fileHash));
                BigInteger amount = Numeric.toBigInt(responseInfo.getContractResult().getResult().toByteArray());
                secondOfflineData.add(new Uint256(amount));
                ContractRequets secondContractRequets = new ContractRequets(chainClientConfig);
                ResultOuterClass.TxResponse seconRresponseInfo = secondContractRequets.requestContract(sysUser, secondParams, secondOfflineData,CertConstants.PUSH_DATA_CHAIN_CONTRACT_NAME,CertConstants.PUSTH_DATA_CHAIN_METHOD_NAME_SET);
                //上个合约地址
                System.out.println("第二次请求合约执行后返回值是:"+ Numeric.toBigInt(seconRresponseInfo.getContractResult().getResult().toByteArray()));

                TableSyncRecord sucSyncRecord = new TableSyncRecord();
                sucSyncRecord.setId(syncID);
                sucSyncRecord.setSyncStatus(1);//同步成功
                tableSyncRecordMapper.updateSynStatus(sucSyncRecord);

          
            } catch (Exception exception) {
                exception.printStackTrace();
                TableSyncRecord failSyncRecord = new TableSyncRecord();
                failSyncRecord.setId(syncID);
                failSyncRecord.setSyncStatus(2);//同步出错
                failSyncRecord.setFailedReason(exception.getMessage());
                tableSyncRecordMapper.updateSynStatus(failSyncRecord);
            }
        }else{
            log.error("ipfs上传文件错误");
        }

链上请求数据的合约方法是getOnlineData

public List<TableRecordDownloadConfig> findByConfigID(String configID) {
        //获取人
        Integer userID = SecurityUtils.getCurrentLoginUser().getSysUser().getUserId();
        //根据人id获取证书
        String signCrtPath= CertConstants.USER_ADMIN_CERT_PATH+userID+"/"+userID+".sign.crt";
        String signKeyPath= CertConstants.USER_ADMIN_CERT_PATH+userID+"/"+userID+".sign.key";
        String tlsCrtPath= CertConstants.USER_ADMIN_CERT_PATH+userID+"/"+userID+".tls.crt";
        String tlsKeyPath= CertConstants.USER_ADMIN_CERT_PATH+userID+"/"+userID+".tls.key";

        try {
            SysUser sysUser = new SysUser();
            sysUser.setSignCrtPath(signCrtPath);
            sysUser.setSignKeyPath(signKeyPath);
            sysUser.setTlsCrtPath(tlsCrtPath);
            sysUser.setTlsKeyPath(tlsKeyPath);

            Map<String, byte[]> params = new HashMap<>();
            //调用合约
            ContractRequets contractRequets = new ContractRequets(chainClientConfig);
            ResultOuterClass.TxResponse responseInfo = contractRequets.requestContract(sysUser, params, null,CertConstants.PUSH_DATA_CHAIN_CONTRACT_NAME,"getAllOfflineData");
            String result = responseInfo.getContractResult().getResult().toStringUtf8();
            log.info("请求合约执行后返回值是:"+ responseInfo);
            //加入缓存
            cacheUtil.addToCache(userID.toString(),result);
            //获取同步的数据状态


            ChainClient chainClient = chainClientConfig.initWithNoConfig(sysUser.getTlsKeyPath(), sysUser.getTlsCrtPath(), sysUser.getSignKeyPath(), sysUser.getSignCrtPath());
            //查询本次交易结果
            log.info("交易id是:"+ responseInfo.getTxId());
            //根据交易id查询交易
            ChainmakerTransaction.TransactionInfo tx = chainClient.getTxByTxId(responseInfo.getTxId(), 1000);
            log.info("本次交易结果是:"+ tx);

            //解析参数
            Request.KeyValuePair keyValuePair = tx.getTransaction().getPayload().getParameters(0);
            log.info("keyValuePair:"+ keyValuePair);
            String v = keyValuePair.getValue().toStringUtf8().substring(0,10);
            log.info("v的结果是:"+v);

            Function f = new Function("getAllOfflineData",
                    Collections.emptyList(),
                    Arrays.asList(
                            new TypeReference<Utf8String>() {},
                            new TypeReference<Utf8String>() {},
                            new TypeReference<Utf8String>() {},
                            new TypeReference<Utf8String>() {},
                            new TypeReference<Utf8String>() {},
                            new TypeReference<Utf8String>() {}
                            )
            );

            String formatted = "0x" + String.format("%64s", v.substring(2)).replace(' ', '0');
            System.out.println(formatted);

            List<Type> typeList = FunctionReturnDecoder.decode(formatted, f.getOutputParameters());

            log.info("解析的参数是::"+ typeList);

        } catch (SdkException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

其中ChainClientConfig代码如下

@Component
public class ChainClientConfig extends org.chainmaker.sdk.config.ChainClientConfig {

    private static final String ORG_CERT_PREFIX="cert/";
    private static final int MAX_MESSAGE_SIZE = 16;

    @Value("${tls_host_name}")
    private String tlsHostName;

    @Value("${node_grpc_url}")
    private String nodeGrpcUrl;

    @Value("${connect_count}")
    private int connectCount;

    @Value("${chain_id}")
    private String chainId;

    @Autowired
    private Environment environment;

    @Autowired
    private ResourceLoader resourceLoader;

    public ChainClient initWithNoConfig(String clientTlsKeyPath, String clientTlsCertPath, String signKeyPath, String signCertPath) throws SdkException, IOException {
        ChainClient chainClient;
        ChainManager chainManager;

        //用yml文件中获取organization,经过判断后从resource文件夹中获取ca证书路径
        String caPath=ORG_CERT_PREFIX + environment.getProperty("organization") + "/ca.crt";
        byte[][] tlsCaCerts = loadCertificate(caPath);

        SdkConfig sdkConfig = new SdkConfig();
        ChainClientConfig chainClientConfig = new ChainClientConfig();
        sdkConfig.setChainClient(chainClientConfig);

        RpcClientConfig rpcClientConfig = new RpcClientConfig();
        rpcClientConfig.setMaxReceiveMessageSize(MAX_MESSAGE_SIZE);

        NodeConfig nodeConfig = new NodeConfig();
        nodeConfig.setTrustRootBytes(tlsCaCerts);
        System.out.println("tlsHostName:"+tlsHostName);
        nodeConfig.setTlsHostName(tlsHostName);
        nodeConfig.setEnableTls(true);
        System.out.println("nodeGrpcUrl:"+nodeGrpcUrl);
        nodeConfig.setNodeAddr(nodeGrpcUrl);
        System.out.println("connectCount:"+connectCount);
        nodeConfig.setConnCnt(connectCount);

        NodeConfig[] nodeConfigs = new NodeConfig[]{nodeConfig};

        chainManager = ChainManager.getInstance();
        chainClient = chainManager.getChainClient(chainId);

        //客户端用户配置
        chainClientConfig.setOrgId(environment.getProperty("organization"));
        chainClientConfig.setChainId(chainId);
        chainClientConfig.setUserKeyBytes(FileUtils.getFileBytes(clientTlsKeyPath));
        chainClientConfig.setUserCrtBytes(FileUtils.getFileBytes(clientTlsCertPath));
        chainClientConfig.setUserSignKeyBytes(FileUtils.getFileBytes(signKeyPath));
        chainClientConfig.setUserSignCrtBytes(FileUtils.getFileBytes(signCertPath));
        chainClientConfig.setRpcClient(rpcClientConfig);
        chainClientConfig.setNodes(nodeConfigs);

        //客户端管理配置
        if (chainClient == null) {
            chainClient = chainManager.createChainClient(sdkConfig);
        }
        return chainClient;
    }

    public byte[][] loadCertificate(String certPath) throws IOException {
        Resource resource = resourceLoader.getResource("classpath:"+certPath);
        try (InputStream inputStream = resource.getInputStream()) {
            byte[] certificateBytes = IOUtils.toByteArray(inputStream);
            return new byte[][] { certificateBytes };
        }
    }
}

其中ContractRequets代码如下

public class ContractRequets {

    private ChainClientConfig chainClientConfig;


    public ContractRequets(ChainClientConfig chainClientConfig) {
        this.chainClientConfig = chainClientConfig;
    }

    public ResultOuterClass.TxResponse requestContract(SysUser sysUser, Map<String, byte[]> firstParams, List<Type> firstOfflineData, String contractName, String methodName) throws SdkException, IOException {
        Function function = new Function(methodName, firstOfflineData==null?Collections.emptyList():firstOfflineData, Collections.emptyList());
        String methodDataStr = FunctionEncoder.encode(function);
        String method = methodDataStr.substring(0, 10);
        firstParams.put(CertConstants.CONTRACT_ARGS_EVM_PARAM, methodDataStr.getBytes());

        //创建链客户端
        ChainClient chainClient = chainClientConfig.initWithNoConfig(sysUser.getTlsKeyPath(), sysUser.getTlsCrtPath(), sysUser.getSignKeyPath(), sysUser.getSignCrtPath());
        ResultOuterClass.TxResponse responseInfo = chainClient.invokeContract(contractName,
                method, null, firstParams, 10000,10000);
        return responseInfo;
    }

}

最后请求后的日志结果如下 image

使用FunctionReturnDecoder.decode(formatted, f.getOutputParameters());解析结果时候,如果直接拿formatted=0x221d1464,如果将 0x221d1464补全64位的话,报错就是上面的错误日志

Edited Sep 26, 2023 by taifu yuan
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
None
Reference: chainmaker/issue#844

Copyright © 2021 ChainMaker Org. All Rights Reserved. 长安链 版权所有。