在fabric区块链网络下,fabric-sdk-java开发的application主要与peer节点交互,通过peer节点提交proposal request,完成背书之后提交到orderer节点进行排序打包。 以下demo使用fabric-sdk-java服务发现API实现查询和提交交易 采用单机部署的raft共识的fabric区块链网络,5个orderer节点,4个peer节点,fabric版本为1.4.6 TestServiceDiscovery.class FabricUser.class 这个异常是因为我的orderer节点在虚拟机上对外开放的端口是10050,但是服务发现在channel中获取到的是7050,因此sdk在使用我们提供的orderer节点的endpoint与orderer通讯的时候会失败,但是交易仍然会成功,原因是服务发现会将开发者手动加入到通道中的orderer节点与其查询出来的orderer节点的信息进行对比,如果两者不同,那么手动加入的orderer节点信息会被删除掉,采用服务发现自动获取的orderer节点。源码如图:
fabric-sdk-java for Service Discovery
前言
在此过程中,若peer节点出现故障,就会导致proposal request提交失败,进而造成application不可用。因此,在fabric 1.2版本中提出了 Service Discovery来解决peer节点高可用的问题。Service Discovery for fabric-sdk-java
此demo使用fabric-java-sd依赖版本为 1.4.8。<!-- https://mvnrepository.com/artifact/org.hyperledger.fabric-sdk-java/fabric-sdk-java --> <dependency> <groupId>org.hyperledger.fabric-sdk-java</groupId> <artifactId>fabric-sdk-java</artifactId> <version>1.4.8</version> </dependency>
代码后面有相关的注意事项,有兴趣的朋友建议看到最后。
本demo采用的fabric网络实例地址:https://download.csdn.net/download/weixin_43562234/12442601代码
package com.richfit.fabric.serviceDiscovery; import com.richfit.fabric.serviceDiscovery.configure.Configurations; import org.hyperledger.fabric.sdk.*; import org.hyperledger.fabric.sdk.security.CryptoSuite; import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; import java.util.concurrent.TimeUnit; public class TestServiceDiscovery { private static final long waitTime = 10000; public static void main(String[] args) throws Exception { //Configurations configurations = new Configurations(); HFClient client = HFClient.createNewInstance(); String userName = "Admin@org1.example.com"; String mspId = "Org1MSP"; String chaincodeName = "mycc"; String keyDir = "src/main/java/com/richfit/fabric/serviceDiscovery/configure/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore"; String keyFile = getKeyFilesInDir(new File(keyDir)).toString(); String certFile = "src/main/java/com/richfit/fabric/serviceDiscovery/configure/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"; //create user object FabricUser user = new FabricUser(userName, mspId, keyFile, certFile); //encryption suite client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite()); client.setUserContext(user); String channelName = "mychannel"; //create channel object Channel channel = client.newChannel(channelName); //create peer0org1 String peer0org1TLSCert = "src/main/java/com/richfit/fabric/serviceDiscovery/configure/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"; Properties peer0org1_properties = new Properties(); peer0org1_properties.put("pemBytes", Files.readAllBytes(Paths.get(peer0org1TLSCert))); peer0org1_properties.setProperty("sslProvider", "openSSL"); peer0org1_properties.setProperty("negotiationType", "TLS"); peer0org1_properties.setProperty("trustServerCertificate", "true"); String peer0org1Name = "peer0.org1.example.com"; String peer0org1URL = "grpcs://peer0.org1.example.com:7051"; peer0org1_properties.setProperty("hostnameOverride", peer0org1Name); Peer peer0org1 = client.newPeer(peer0org1Name, peer0org1URL, peer0org1_properties); //create peer1org1 String peer1org1TLSCert = "src/main/java/com/richfit/fabric/serviceDiscovery/configure/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt"; Properties peer1org1_properties = new Properties(); peer1org1_properties.put("pemBytes", Files.readAllBytes(Paths.get(peer1org1TLSCert))); peer1org1_properties.setProperty("sslProvider", "openSSL"); peer1org1_properties.setProperty("negotiationType", "TLS"); peer1org1_properties.setProperty("trustServerCertificate", "true"); String peer1org1Name = "peer1.org1.example.com"; String peer1org1URL = "grpcs://peer1.org1.example.com:8051"; peer1org1_properties.setProperty("hostnameOverride", peer1org1Name); Peer peer1org1 = client.newPeer(peer1org1Name, peer1org1URL, peer1org1_properties); //create peer0org2 String peer0org2TLSCert = "src/main/java/com/richfit/fabric/serviceDiscovery/configure/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"; Properties peer0org2_properties = new Properties(); peer0org2_properties.put("pemBytes", Files.readAllBytes(Paths.get(peer0org2TLSCert))); peer0org2_properties.setProperty("sslProvider", "openSSL"); peer0org2_properties.setProperty("negotiationType", "TLS"); peer0org2_properties.setProperty("trustServerCertificate", "true"); String peer0org2Name = "peer0.org2.example.com"; String peer0org2URL = "grpcs://peer0.org2.example.com:9051"; peer0org2_properties.setProperty("hostnameOverride", peer0org2Name); Peer peer0org2 = client.newPeer(peer0org2Name, peer0org2URL, peer0org2_properties); //create peer1org2 String peer1org2TLSCert = "src/main/java/com/richfit/fabric/serviceDiscovery/configure/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt"; Properties peer1org2_properties = new Properties(); peer1org2_properties.put("pemBytes", Files.readAllBytes(Paths.get(peer1org2TLSCert))); peer1org2_properties.setProperty("sslProvider", "openSSL"); peer1org2_properties.setProperty("negotiationType", "TLS"); peer1org2_properties.setProperty("trustServerCertificate", "true"); String peer1org2Name = "peer1.org2.example.com"; String peer1org2URL = "grpcs://peer1.org2.example.com:10051"; peer1org2_properties.setProperty("hostnameOverride", peer1org2Name); Peer peer1org2 = client.newPeer(peer1org2Name, peer1org2URL, peer1org2_properties); channel.addPeer(peer0org1, Channel.PeerOptions.createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY, Peer.PeerRole.LEDGER_QUERY, Peer.PeerRole.EVENT_SOURCE, Peer.PeerRole.CHAINCODE_QUERY))); channel.addPeer(peer1org1, Channel.PeerOptions.createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY, Peer.PeerRole.LEDGER_QUERY, Peer.PeerRole.EVENT_SOURCE, Peer.PeerRole.CHAINCODE_QUERY))); channel.addPeer(peer0org2, Channel.PeerOptions.createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY, Peer.PeerRole.LEDGER_QUERY, Peer.PeerRole.EVENT_SOURCE, Peer.PeerRole.CHAINCODE_QUERY))); channel.addPeer(peer1org2, Channel.PeerOptions.createPeerOptions().setPeerRoles(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY, Peer.PeerRole.LEDGER_QUERY, Peer.PeerRole.EVENT_SOURCE, Peer.PeerRole.CHAINCODE_QUERY))); //init channel channel.initialize(); //queryByChaincode(client, chaincodeName, channel); insertByChaincode(client,chaincodeName,channel); } public static void queryByChaincode(HFClient client, String chaincodeName , Channel channel) throws Exception { ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(chaincodeName).build(); //build args ArrayList<String> argsList = new ArrayList<>(); argsList.add("a"); String function = "query"; executeTransaction(client, channel, chaincodeID,false, function, argsList); } public static void insertByChaincode(HFClient client, String chaincodeName , Channel channel) throws Exception { ChaincodeID chaincodeID = ChaincodeID.newBuilder().setName(chaincodeName).build(); ArrayList<String> argsList = new ArrayList<>(); argsList.add("b"); argsList.add("a"); argsList.add("10"); String function = "invoke"; executeTransaction(client, channel, chaincodeID,true ,function, argsList); } private static void executeTransaction(HFClient client, Channel channel, ChaincodeID chaincodeID, boolean invoke, String func, ArrayList<String> args) throws Exception { TransactionProposalRequest transactionProposalRequest = client.newTransactionProposalRequest(); transactionProposalRequest.setChaincodeID(chaincodeID); transactionProposalRequest.setChaincodeLanguage(TransactionRequest.Type.JAVA); transactionProposalRequest.setFcn(func); transactionProposalRequest.setArgs(args); transactionProposalRequest.setProposalWaitTime(waitTime); List<ProposalResponse> successful = new LinkedList<ProposalResponse>(); List<ProposalResponse> failed = new LinkedList<ProposalResponse>(); // java sdk // 通常会发送交易请求给所有peer节点,如果有一些peer节点宕机,但是有Response到达了背书节点的话,我们可以不选择重新发送交易请求,使用服务发现功能可以实现这一目标。 Collection<ProposalResponse> transactionPropResp; // 确保配置有服务发现功能的peer节点数量大于0 if (channel.getPeers(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY)).size() > 0) { System.out.println("配置有服务发现功能的peer节点数量:" + channel.getPeers(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY)).size()); // 配置服务发现在fabric网络中,使用服务发现来寻找背书节点(endorsing peers) Channel.DiscoveryOptions discoveryOptions = Channel.DiscoveryOptions.createDiscoveryOptions(); // 随机选取满足背书策略的peer节点组合 ENDORSEMENT_SELECTION_RANDOM // 选取满足背书策略的,状态最新、块高最大的peer节点组合 ENDORSEMENT_SELECTION_LEAST_REQUIRED_BLOCKHEIGHT discoveryOptions.setEndorsementSelector(ServiceDiscovery.EndorsementSelector.ENDORSEMENT_SELECTION_RANDOM); // discoveryOptions.setEndorsementSelector(ServiceDiscovery.EndorsementSelector.ENDORSEMENT_SELECTION_LEAST_REQUIRED_BLOCKHEIGHT); // setForceDiscovery true :每一次发送proposal时都调用discovery服务获取peer列表,会有一定的资源消耗 // setForceDiscovery false :发送proposal时使用discovery服务缓存的peer列表,默认2分钟刷新一次 discoveryOptions.setForceDiscovery(false); // setInspectResults true: 关闭SDK 背书策略检查,由应用逻辑进行判断 // false:SDK 自动进行背书策略检查,不满足抛出异常 discoveryOptions.setInspectResults(true); transactionPropResp = channel.sendTransactionProposalToEndorsers(transactionProposalRequest, discoveryOptions); } else { System.out.println("peers:" + channel.getPeers(EnumSet.of(Peer.PeerRole.SERVICE_DISCOVERY)).size()); transactionPropResp = channel.sendTransactionProposal(transactionProposalRequest, channel.getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER))); } for (ProposalResponse response : transactionPropResp) { System.out.println("ChaincodeActionResponseStatus:"+response.getChaincodeActionResponseStatus()); System.out.println("ChaincodeActionResponsePayload:"+ Arrays.toString(response.getChaincodeActionResponsePayload())); System.out.println(""+response.getProposalResponse()); //System.out.println(); if (response.getStatus() == ProposalResponse.Status.SUCCESS) { String payload = response.getProposalResponse().getResponse().getPayload().toStringUtf8(); if (payload.isEmpty()) { System.out.println("******************************************************************************"); System.out.println(String.format("[√] 得到成功响应从 peer %s", response.getPeer().getName())); } else { System.out.println("******************************************************************************"); System.out.println( String.format("[√] 得到成功响应从 peer %s => payload: %s", response.getPeer().getName(), payload)); } successful.add(response); } else { String status = response.getStatus().toString(); String msg = response.getMessage(); System.out.println(String.format("[×] 响应失败从 peer %s => %s: %s ", response.getPeer().getName(), status, msg)); failed.add(response); } } if (invoke) { Channel.TransactionOptions opts = new Channel.TransactionOptions(); Channel.NOfEvents nOfEvents = Channel.NOfEvents.createNofEvents(); nOfEvents.addPeers(channel.getPeers(EnumSet.of(Peer.PeerRole.EVENT_SOURCE))); nOfEvents.setN(1); opts.nOfEvents(nOfEvents); System.out.println("向orderers发送交易..."); channel.sendTransaction(successful, opts).thenApply(transactionEvent -> { System.out.println("Orderer 响应: txid" + transactionEvent.getTransactionID()); System.out.println("Orderer 响应: 区块编号: " + transactionEvent.getBlockEvent().getBlockNumber()); return null; }).exceptionally(e -> { System.out.println("Orderer exception happened: "+ e); return null; }).get(waitTime, TimeUnit.SECONDS); } } private static File getKeyFilesInDir(File filePath) { File keyFile = null; File[] listFiles = filePath.listFiles(); if (listFiles != null) { for (File file : listFiles) { if (file.isFile()) { if (file.getName().endsWith("_sk")) { keyFile = file; break; } } } } return keyFile; } }
package com.richfit.fabric.serviceDiscovery; import org.hyperledger.fabric.sdk.Enrollment; import org.hyperledger.fabric.sdk.User; import org.hyperledger.fabric.sdk.identity.X509Enrollment; import org.hyperledger.fabric.sdk.security.CryptoPrimitives; import java.nio.file.Files; import java.nio.file.Paths; import java.security.PrivateKey; import java.util.Set; /** * @author adder * @date 2020/1/20 15:43 */ public class FabricUser implements User { private String name; private String mspId; private Enrollment enrollment; private String keyFile; private String certFile; public FabricUser(String name, String mspId, String keyFile, String certFile) { this.name = name; this.mspId = mspId; this.keyFile=keyFile; this.certFile=certFile; try{ enrollment=loadFromPemFile(keyFile, certFile); }catch(Exception ex){ ex.printStackTrace(); } } private Enrollment loadFromPemFile(String keyFile,String certFile) throws Exception{ byte[] keyPem = Files.readAllBytes(Paths.get(keyFile)); //load private key text byte[] certPem = Files.readAllBytes(Paths.get(certFile)); //load certificate text CryptoPrimitives suite = new CryptoPrimitives(); //load the cryptography suite PrivateKey privateKey = suite.bytesToPrivateKey(keyPem); //convert private key text to object return new X509Enrollment(privateKey,new String(certPem)); //create X509Enrollment object } @Override public String getName() { return name; } @Override public String getMspId() { return mspId; } @Override public Enrollment getEnrollment() { return enrollment; } @Override public String getAccount() { return null; } @Override public String getAffiliation() { return null; } @Override public Set<String> getRoles() { return null; } public String getKeyFile() { return keyFile; } public void setKeyFile(String keyFile) { this.keyFile = keyFile; } public String getCertFile() { return certFile; } public void setCertFile(String certFile) { this.certFile = certFile; } }
注意!!!
CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:8051
配置,来实现peer节点主动向channel中广播自己的状态。ORDERER_GENERAL_LISTENPORT=7050
环境变量的端口号,使其与orderer节点在服务器上对外暴露的端口保持一致,否则在使用sdk调用服务发现API的时候会出现异常,异常信息如下:19:10:04.242 [main] DEBUG org.hyperledger.fabric.sdk.Orderer - Orderer.sendTransaction Orderer{id: 18, channelName: mychannel, name:orderer4.example.com:7050, url: grpcs://orderer4.example.com:7050} 19:10:04.244 [main] DEBUG org.hyperledger.fabric.sdk.Endpoint - Endpoint grpcs://orderer4.example.com:7050 with no ssl context 19:10:04.254 [grpc-default-worker-ELG-1-16] DEBUG io.netty.handler.ssl.ReferenceCountedOpenSslContext - verification of certificate failed java.security.cert.CertificateException: No subject alternative DNS name matching orderer4.example.com found. at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:214) at sun.security.util.HostnameChecker.match(HostnameChecker.java:96) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) at io.netty.handler.ssl.OpenSslTlsv13X509ExtendedTrustManager.checkServerTrusted(OpenSslTlsv13X509ExtendedTrustManager.java:223) at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:255) at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:701) at io.netty.internal.tcnative.SSL.readFromSSL(Native Method) at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.readPlaintextData(ReferenceCountedOpenSslEngine.java:593) at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1176) at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1293) at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1336) at io.netty.handler.ssl.SslHandler$SslEngineType$1.unwrap(SslHandler.java:204) at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1332) at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1227) at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1274) at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:503) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:281) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748) 19:10:04.259 [grpc-default-executor-1] ERROR org.hyperledger.fabric.sdk.OrdererClient - OrdererClient{id: 23, channel: mychannel, name: orderer4.example.com:7050, url: grpcs://orderer4.example.com:7050} managed channel isTerminated: false, isShutdown: false, state: TRANSIENT_FAILURE 19:10:04.259 [grpc-default-executor-1] ERROR org.hyperledger.fabric.sdk.OrdererClient - Received error org.hyperledger.fabric.sdk.OrdererClient$1@6e8ba5db UNAVAILABLE: io exception io.grpc.StatusRuntimeException: UNAVAILABLE: io exception at io.grpc.Status.asRuntimeException(Status.java:530) at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:434) at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39) at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) at io.grpc.internal.CensusStatsModule$StatsClientInterceptor$1$1.onClose(CensusStatsModule.java:694) at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39) at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) at io.grpc.internal.CensusTracingModule$TracingClientInterceptor$1$1.onClose(CensusTracingModule.java:397) at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:459) at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:63) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:546) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$600(ClientCallImpl.java:467) at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:584) at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.handshakeException(ReferenceCountedOpenSslEngine.java:1732) at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.wrap(ReferenceCountedOpenSslEngine.java:774) at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:509) at io.netty.handler.ssl.SslHandler.wrap(SslHandler.java:1046) at io.netty.handler.ssl.SslHandler.wrapNonAppData(SslHandler.java:937) at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1395) at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1227) at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1274) at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:503) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:442) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:281) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ... 1 common frames omitted
结合fabric网络分析:orderer节点在channel中广播的endpoint则是域名:LISTENPORT
,那么service discovery在channel中查询到的orderer节点的endpoint就是域名:7050
,因此在使用sdk开发application的时候需要注意一下。如果demo测试过程中出现了问题,欢迎在本博客下留言,笔者会及时回复
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算