Java sdk连接fabric网络的谜之报错

4 篇文章 0 订阅

谜之报错

下面是一个使用fabric-java-sdk和fabric-java-gateway尝试连接上述虚拟机的未解决的一堆报错。更离谱的是,每一次报错都还不一样。。。

由于这是一个未解决的连接错误,我只阐述我做了什么和得到的反馈,也希望有类似经历的伙伴提供一些建议。

connection.json配置文件

{
  "name": "basic-network",
  "version": "1.0.0",
  "dependencies": {
  },
  "client": {
    "organization": "Department1",
    "connection": {
      "timeout": {
        "peer": {
          "endorser": "30000"
        },
        "orderer": "30000"
      }
    },
    "organization": "Department2",
    "connection": {
      "timeout": {
        "peer": {
          "endorser": "30000"
        },
        "orderer": "30000"
      }
    }
  },
  "channels": {
    "tracechannel": {
      "orderers": [
        "orderer.trace.com"
      ],
      "peers": {
        "peer0.department1.trace.com": {
          "endorsingPeer": true,
          "chaincodeQuery": true,
          "ledgerQuery": true,
          "eventSource": true
        },

        "peer0.department2.trace.com": {
          "endorsingPeer": true,
          "chaincodeQuery": true,
          "ledgerQuery": true,
          "eventSource": true
        },

      }
    }
  },
  "organizations": {
    "Department1": {
      "mspid": "Department1MSP",
      "peers": [
        "peer0.department1.trace.com",
      ],
      "adminPrivateKeyPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/department1.trace.com/users/Admin@department1.trace.com/msp/keystore/priv_sk"
      },
      "signedCertPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/department1.trace.com/users/Admin@department1.trace.com/msp/signcerts/Admin@department1.trace.com-cert.pem"
      }
    },
    "Department2": {
      "mspid": "Department2MSP",
      "peers": [
        "peer0.department2.trace.com",
      ],
      "adminPrivateKeyPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/department2.trace.com/users/Admin@department2.trace.com/msp/keystore/priv_sk"
      },
      "signedCertPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/department2.trace.com/users/Admin@department2.trace.com/msp/signcerts/Admin@department2.trace.com-cert.pem"
      }
    }
  },

      "mspid": "OrdererMSP",
      "grpcOptions": {"orderers": {
        "orderer.trace.com": {
          "url": "grpcs://127.0.0.1:7050",
        "ssl-target-name-override": "orderer.trace.com",
        "hostnameOverride": "orderer.trace.com"
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/ordererOrganizations/trace.com/orderers/orderer.trace.com/tls/ca.crt"
      },
      "adminPrivateKeyPEM": {
        "path": "src/main/resources/crypto-config/ordererOrganizations/trace.com/users/Admin@trace.com/msp/keystore/priv_sk"
      },
      "signedCertPEM": {
        "path": "src/main/resources/crypto-config/ordererOrganizations/trace.com/users/Admin@trace.com/msp/signcerts/Admin@trace.com-cert.pem"
      }
    }
  },
  "peers": {
    "peer0.department1.trace.com": {
      "url": "grpcs://127.0.0.1:7051",
      "grpcOptions": {
        "ssl-target-name-override": "peer0.department1.trace.com",
        "hostnameOverride": "peer0.department1.trace.com",
        "request-timeout": 120001
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/peerOrganizations/department1.trace.com/peers/peer0.department1.trace.com/tls/ca.crt"
      }
    },

    "peer0.department2.trace.com": {
      "url": "grpcs://127.0.0.1:8051",
      "grpcOptions": {
        "ssl-target-name-override": "peer0.department2.trace.com",
        "hostnameOverride": "peer0.department2.trace.com",
        "request-timeout": 120001
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/peerOrganizations/department2.trace.com/peers/peer0.department2.trace.com/tls/ca.crt"
      }
    },

  }
}

官方案例测试Sample.java

package com.zcongfly;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.hyperledger.fabric.gateway.*;
import org.hyperledger.fabric.gateway.impl.GatewayImpl;
import org.hyperledger.fabric.sdk.HFClient;

import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * @author admin
 */
public class Sample {
    private Gateway gateway;
    private Network network;
    private static final Path NETWORK_CONFIG_PATH = Paths.get("src","main", "resources", "connection.json");
    private static final Path credentialPath = Paths.get("src","main","resources", "crypto-config", "peerOrganizations", "department1.trace.com", "users", "User1@department1.trace.com", "msp");
    public static void main(String[] args) throws IOException {
        X509Certificate certificate = null;
        PrivateKey privateKey = null;
        Gateway gateway = null;
        try {
            //使用org1中的user1初始化一个网关wallet账户用于连接网络
            Wallet wallet = Wallets.newInMemoryWallet();
            Path certificatePath = credentialPath.resolve(Paths.get("signcerts", "User1@department1.trace.com-cert.pem"));

            certificate = readX509Certificate(certificatePath);
            Path privateKeyPath = credentialPath.resolve(Paths.get("keystore", "priv_sk"));

            privateKey = getPrivateKey(privateKeyPath);
            wallet.put("user",Identities.newX509Identity("Department1MSP",certificate,privateKey));
            //根据connection.json 获取Fabric网络连接对象
            GatewayImpl.Builder builder = (GatewayImpl.Builder) Gateway.createBuilder();
            builder.identity(wallet, "user").networkConfig(NETWORK_CONFIG_PATH);
            //连接网关
            gateway = builder.connect();
            System.out.println("=====================已连接到网关!=======================");
            //获取mychannel通道
            Network network = gateway.getNetwork("mychannel");
            System.out.println(network);
            System.out.println("===================已连接到指定通道!========================================");
            //获取合约对象
            Contract myoilcc = network.getContract("myoilcc");
            System.out.println(myoilcc);
            // 提交事务 存储到账本
            //byte[] createSaccResult = myprovocoilContract.createTransaction("addoilaccount").submit("3","2022.04.21","136.0","3","1","","36");
            //System.out.println("myprovocoil油料存储:" + new String(createSaccResult, StandardCharsets.UTF_8));

            // 查询
            //byte[] queSaccResult = myprovocoilContract.createTransaction("query").submit("001油品");
            //System.out.println("myprovocoil油料查询结果:" + new String(queSaccResult, StandardCharsets.UTF_8));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从文件或流中读取X.509证书并返回一个X509Certificate对象。
     *X.509证书是一种数字证书格式,常用于加密、签名和身份验证等安全应用程序中。
     * 在Hyperledger Fabric中,X.509证书也被广泛用于身份验证和授权。
     * 使用Java编写的Hyperledger Fabric客户端应用程序通常需要读取和解析X.509证书以进行身份验证和交易提交。
     * readX509Certificate方法接受一个InputStream参数,该参数指定了包含X.509证书数据的输入流。
     * 该方法首先创建一个CertificateFactory实例,并使用该实例从输入流中加载证书数据并返回一个X509Certificate对象。
     */
    private static X509Certificate readX509Certificate(final Path certificatePath) throws IOException, CertificateException {
        try (Reader certificateReader =
                     Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
            return Identities.readX509Certificate(certificateReader);
        }
    }

    /**
     * 从文件或流中读取私钥数据并返回一个PrivateKey对象。
     * 在Hyperledger Fabric中,使用X.509证书进行身份验证和授权时,通常需要提供与证书关联的私钥。
     * 使用Java编写的Hyperledger Fabric客户端应用程序通常需要读取和解析私钥以进行身份验证和交易提交。
     * getPrivateKey方法接受两个参数,分别是包含私钥数据的InputStream对象和私钥的密码。
     * 该方法首先创建一个KeyStore实例,并使用该实例从输入流中加载私钥数据和相关证书链。
     * 然后,该方法使用密码解密私钥数据,并返回一个PrivateKey对象。
     */
    private static PrivateKey getPrivateKey(final Path privateKeyPath) throws IOException, InvalidKeyException {
        try (Reader privateKeyReader =
                     Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
            return Identities.readPrivateKey(privateKeyReader);
        }
    }
}

报错1:

虚拟机使用的是NAT模式,已开启ssh服务,并在虚拟机上设置了端口转发,将22端口映射成主机上的2222端口,目前主机可以通过ssh命令连接到虚拟机,命令是ssh username@127.0.0.1 -p 2222,但是再使用fabric-java-sdk连接连接到该虚拟机上启动的fabric网络时一直报错,目前主机仍然无法ping通虚拟机的ip地址,只能通过ssh username@127.0.0.1 -p 2222命令与虚拟机进行连接和通信。

以下是connection.json的当前配置:

"orderers": {
    "orderer.trace.com": {
      "url": "grpcs://localhost:7050",

不论将url改成127.0.0.1、localhost、虚拟机ip、虚拟机内部IP均报错Connection refused

ERROR org.hyperledger.fabric.sdk.Channel - Channel Channel{id: 1, name: mychannel} Sending proposal with transaction: 7d61cbf1e1cbdab5a17d552254cd5957bbd19006813169c2c6031e90dfd384ae to Peer{ id: 2, name: peer0.department2.trace.com, channelName: mychannel, url: grpcs://localhost:8051, mspid: Department2MSP} failed because of: gRPC failure=Status{code=UNAVAILABLE, description=io exception, cause=io.grpc.netty.shaded.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/[0:0:0:0:0:0:0:1]:8051
Caused by: java.net.ConnectException: Connection refused: no further information

将url改为grpcs://localhost:2222,报错Connection refused

ERROR org.hyperledger.fabric.sdk.Channel - Channel Channel{id: 1, name: mychannel} Sending proposal with transaction: ca2ff093f2624894dc15a90ef9f7f497d5510fad9e3e29663a143b1609007447 to Peer{ id: 2, name: peer0.department2.trace.com, channelName: mychannel, url: grpcs://localhost:2222, mspid: Department2MSP} failed because of: gRPC failure=Status{code=UNAVAILABLE, description=io exception, cause=io.grpc.netty.shaded.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: localhost/[0:0:0:0:0:0:0:1]:2222
Caused by: java.net.ConnectException: Connection refused: no further information

这应该属于同一类错误。

报错2:

查阅资料,启用ssh隧道:

ssh -L 5000:localhost:5000 zcongfly@127.0.0.1 -p 2222

修改所有节点的grpc的url为:

"url": "grpcs://localhost:5000",

报错变成了Connection reset

ERROR org.hyperledger.fabric.sdk.Channel - Channel Channel{id: 1, name: mychannel} Sending proposal with transaction: d98f80a464b5011fa2cbee88d74a6ce8bcab09c39244bb0670ccabd2325b9347 to Peer{ id: 2, name: peer0.department2.trace.com, channelName: mychannel, url: grpcs://127.0.0.1:5000, mspid: Department2MSP} failed because of: gRPC failure=Status{code=UNAVAILABLE, description=io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0], cause=java.net.SocketException: Connection reset

报错3:

进一步查阅资料:

https://stackoverflow.com/questions/62897216/why-am-i-getting-tls-handshake-error-when-i-try-to-connect-from-hyperledger-java

https://stackoverflow.com/questions/53625506/hyperledger-fabric-java-sdk-use-grpcs-for-peer-and-orderer-connections/53676602?r=SearchResults&s=2%7C14.4806#53676602

在crypto-config.ymal中添加SANS:

SANS:
	- "localhost"

在Java工程的src/main/resources文件夹下以管理员身份运行cmd,输入命令:

# 添加证书到java的jvm密钥库中
keytool -import -file crypto-config\peerOrganizations\department2.trace.com\peers\peer0.department2.trace.com\tls\server.crt -alias peer0.department2.trace.com -keystore "C:\Program Files\Java\jre1.8.0_281\lib\security\cacerts" -storepass changeit
keytool -import -file crypto-config\peerOrganizations\department1.trace.com\peers\peer0.department1.trace.com\tls\server.crt -alias peer0.department1.trace.com -keystore "C:\Program Files\Java\jre1.8.0_281\lib\security\cacerts" -storepass changeit
keytool -import -file crypto-config\ordererOrganizations\trace.com\orderers\orderer.trace.com\tls\server.crt -alias orderer.trace.com -keystore "C:\Program Files\Java\jre1.8.0_281\lib\security\cacerts" -storepass changeit

再次运行Sample.java,报错你的主机中的软件中止了一个已建立的连接

ERROR org.hyperledger.fabric.sdk.Channel - Channel Channel{id: 1, name: mychannel} Sending proposal with transaction: 9f9972c50afe9e23dd8ba4a9ca1cb9d81ec950b53bcc51d75991adf601b66964 to Peer{ id: 2, name: peer0.department2.trace.com, channelName: mychannel, url: grpcs://127.0.0.1:5000, mspid: Department2MSP} failed because of: gRPC failure=Status{code=UNAVAILABLE, description=io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0], cause=java.io.IOException: 你的主机中的软件中止了一个已建立的连接。

这个错误在网上倒也能找到些东西,也是Java连接远程数据库啥的。大致就是有可能虚拟机那边响应慢,sdk发送ssl连接请求时没等响应就断开或者发了一个新的请求,把连接中断了;或者是设置了timeout,超时就直接给断开了连接;又或者是短时间内重复提交了同一个表单导致连接中断,总之,都不是我这类情况。

参考:https://blog.csdn.net/qq_54070103/article/details/127441068

https://www.bbsmax.com/A/qVdepjbr5P/

此时,每运行一次Simple.java,cmd窗口中开始不断显示channel 3: open failed: connect failed: Connection refused

C:\WINDOWS\system32>ssh -L 7050:localhost:7050 zcongfly@127.0.0.1 -p 2222
zcongfly@127.0.0.1's password:
Last login: Fri Mar 31 08:15:03 2023 from gateway
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused
[zcongfly@localhost ~]$ channel 3: open failed: connect failed: Connection refused

这一度带给过我希望,是不是只要解决了信任问题就可以连接上了。

报错4:

求助于chat-gpt:

“如果您使用SSH端口转发将CentOS虚拟机上的peer节点端口映射到本地主机上的端口,则您可以在url中指定本地主机上的端口。在这种情况下,您应该将localhost设置为本地主机的IP地址(通常为127.0.0.1),并将端口设置为您在SSH端口转发命令中指定的本地端口(默认为2222)。

例如,如果您在本地主机上执行了以下SSH端口转发命令:

ssh -L 2222:localhost:7051 user@192.168.1.100

则您的url应该类似于:

"url": "grpc://127.0.0.1:2222"

这将允许Java SDK客户端通过本地主机上的端口2222连接到CentOS虚拟机上的peer节点的GRPC服务。”
如果要连接多个peer节点该如何操作呢?比如连接到peer0的7051端口、peer1的8051端口、peer2的9051端口?

如果要连接多个peer节点,您需要为每个peer节点执行SSH端口转发命令,并将它们映射到本地主机的不同端口。例如:

ssh -L 2222:localhost:7051 user@192.168.1.100
ssh -L 3333:localhost:8051 user@192.168.1.100
ssh -L 4444:localhost:9051 user@192.168.1.100

以上命令将分别将CentOS虚拟机上peer0、peer1和peer2的GRPC服务端口映射到本地端口2222、3333和4444上。

接下来,您可以在Java SDK客户端中使用以下代码来连接这些peer节点:

List<Peer> peers = new ArrayList<>();
peers.add(HFClient.createNewDefaultPeer("peer0", "grpc://127.0.0.1:2222"));
peers.add(HFClient.createNewDefaultPeer("peer1", "grpc://127.0.0.1:3333"));
peers.add(HFClient.createNewDefaultPeer("peer2", "grpc://127.0.0.1:4444"));

Channel channel = HFClient.createNewChannel("mychannel", orderer, config);
channel.addPeers(peers);

以上代码创建了一个包含所有peer节点的peers列表,并将其添加到一个名为mychannel的通道中。请注意,在每个grpc:// URL中,您需要指定正确的本地端口,以便连接到相应的peer节点。

这样,您就可以通过Java SDK客户端连接到多个peer节点的GRPC服务了。

先到虚拟机中在添加3333和4444的端口转发,然后以管理员身份启用3个cmd窗口,分别输入:

ssh -L 7050:localhost:7050 zcongfly@127.0.0.1 -p 2222
ssh -L 7051:localhost:7051 zcongfly@127.0.0.1 -p 3333
ssh -L 8051:localhost:8051 zcongfly@127.0.0.1 -p 4444

建立起3个ssh隧道并成功连接上之后,修改connection.json文件中各个节点url分别为:

"url": "grpcs://localhost:7050"
"url": "grpcs://localhost:7051"
"url": "grpcs://localhost:8051"

运行Sample.java,报错Connection closed while performing TLS negotiation

ERROR org.hyperledger.fabric.sdk.Channel - Channel Channel{id: 1, name: mychannel} Sending proposal with transaction: d2915393c441925665cb31c87a9c1803c0022707b124e35f27e72c20e762fedd to Peer{ id: 2, name: peer0.department2.trace.com, channelName: mychannel, url: grpcs://127.0.0.1:8051, mspid: Department2MSP} failed because of: gRPC failure=Status{code=UNAVAILABLE, description=Connection closed while performing TLS negotiation
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0], cause=java.nio.channels.ClosedChannelExceptionERROR org.hyperledger.fabric.sdk.Channel - Channel Channel{id: 1, name: mychannel} Sending proposal with transaction: d2915393c441925665cb31c87a9c1803c0022707b124e35f27e72c20e762fedd to Peer{ id: 2, name: peer0.department2.trace.com, channelName: mychannel, url: grpcs://127.0.0.1:8051, mspid: Department2MSP} failed because of: gRPC failure=Status{code=UNAVAILABLE, description=Connection closed while performing TLS negotiation

这回变为TSL证书错误了。。。

这个错误表明在与peer节点进行TLS协商期间,连接已经被关闭,导致无法发送建议。这通常表示由于某些网络问题或配置错误而无法建立稳定的TLS连接。

您可以尝试检查以下几点:

  1. 确认您的peer节点是否正确启动并正在运行。您可以使用peer node status命令来检查。

  2. 检查peer节点的TLS证书和密钥是否正确生成,并且Java SDK客户端是否正确加载了这些证书和密钥。您可以检查SDK客户端的TLS设置,并确保它们与peer节点的TLS设置匹配。

  3. 检查您的网络环境,确保从Java SDK客户端到peer节点的网络连接是可用的,并且没有任何防火墙或网络代理阻止了通信。

如果您仍然无法解决问题,请尝试将日志级别设置为更高的水平,并检查详细的日志信息,以便更好地理解问题所在。

要检查Java SDK客户端中使用的TLS配置和证书,您可以检查以下内容:

  1. 客户端配置文件:检查您在创建SDK客户端时传递的配置文件。如果您使用了默认配置,该文件应为connection-profile.yaml

  2. TLS证书和密钥:检查配置文件中包含的TLS证书和密钥路径是否正确,并确保这些证书和密钥与peer节点的TLS设置匹配。

  3. TLS设置:检查配置文件中的TLS设置,例如是否启用了TLS,是否使用了正确的加密算法等。确保客户端的TLS设置与peer节点的TLS设置匹配。

  4. 日志输出:启用更详细的日志输出,以便检查TLS握手期间发生的任何错误或异常情况。您可以通过在SDK客户端代码中调用Logger.getLogger("org.hyperledger.fabric").setLevel(Level.DEBUG)来设置更高的日志级别。这将打印出更多的详细信息,包括TLS握手期间发生的事件和错误。

  5. 测试工具:您可以使用OpenSSL等工具测试从SDK客户端到peer节点的TLS连接是否正常工作。例如,您可以使用以下命令来测试与peer节点的TLS连接:

openssl s_client -connect <peer-hostname>:<peer-port> -tls1_2

以上命令将使用TLS 1.2连接到指定的peer节点,并打印出与TLS握手相关的详细信息。如果该命令能够成功连接到peer节点并打印出TLS握手信息,则可以确认TLS配置和证书设置正确。

(一下午了,Java也好fabric也罢,求求你们做个人吧。。。)

TSL一下触及到知识盲区了,其实前边的ssh和什么ssl连接的Java密钥就已经是盲区了。

先记录下,让我歇会儿。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
连接虚拟机区块链网络,需要进行以下步骤: 1. 安装 Hyperledger Fabric 网络,并确保网络正在运行。 2. 下载并安装 fabric-sdk-java。 3. 创建一个 Java 应用程序,并将 fabric-sdk-java 添加到类路径中。 4. 在 Java 应用程序中创建一个 Fabric 客户端对象,并指定连接的节点信息。 5. 使用客户端对象创建一个 Fabric 通道对象,并向通道添加一个或多个对等方和一个或多个排序服务。 6. 在通道对象中定义和安装链码。 7. 使用客户端对象调用链码函数。 下面是一个简单的示例代码,展示如何连接虚拟机区块链网络。 ```java import org.hyperledger.fabric.sdk.*; import org.hyperledger.fabric.sdk.exception.*; public class FabricClient { private HFClient client; private Channel channel; public FabricClient() throws Exception { client = HFClient.createNewInstance(); // 设置连接信息 String peerUrl = "grpc://localhost:7051"; String ordererUrl = "grpc://localhost:7050"; String pemFile = "/path/to/pem/file"; String userName = "user1"; String orgName = "org1"; // 创建一个 Fabric 用户对象 User user = new FabricUser(userName, orgName, pemFile); // 初始化客户端对象 client.setUserContext(user); client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite()); // 创建一个 Fabric 通道对象 channel = client.newChannel("mychannel"); // 添加对等方节点 Peer peer = client.newPeer("peer1", peerUrl); channel.addPeer(peer); // 添加排序服务节点 Orderer orderer = client.newOrderer("orderer", ordererUrl); channel.addOrderer(orderer); // 初始化通道对象 channel.initialize(); } public String invokeChaincode(String functionName, String... args) throws Exception { // 创建一个链码调用请求对象 TransactionProposalRequest request = client.newTransactionProposalRequest(); ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName("mychaincode").build(); request.setChaincodeID(chaincodeID); request.setFcn(functionName); request.setArgs(args); // 发送链码调用请求并等待响应 Collection<ProposalResponse> responses = channel.sendTransactionProposal(request); for (ProposalResponse response : responses) { if (response.getStatus() != ChaincodeResponse.Status.SUCCESS) { throw new Exception("Chaincode invoke failed: " + response.getMessage()); } } // 提交链码调用事务 channel.sendTransaction(responses); return "Chaincode invoke succeeded"; } } ``` 在这个示例代码中,我们创建了一个名为 FabricClient 的 Java 类,它充当了 Fabric 客户端的角色。在构造函数中,我们初始化了客户端对象,并连接了一个名为 mychannel 的 Fabric 通道。然后,我们定义了一个名为 invokeChaincode 的函数,该函数接受一个链码函数名和一个或多个参数,并将其用作链码调用请求。最后,我们向通道提交了链码调用事务。 要使用这个示例代码,您需要将其添加到一个 Java 应用程序中,并在应用程序中创建一个 FabricClient 对象。然后,您可以使用 FabricClient 对象调用 invokeChaincode 函数来调用链码函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zcongfly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值