我正在使用Hyperledger Fabric v1.4 first-network 示例来设置具有两个组织和四个对等点的区块链网络。这是使用设置运行的 docker 进程的屏幕截图。
第一个网络示例使用背书策略,AND ('Org1MSP.peer','Org2MSP.peer')
默认链码为chaincode_example02
为了与网络通信,我使用的是 JAVA SDK v1.4.1。我能够注册创建 HF 客户端和频道等,还能够创建用户和查询(读取)区块链而没有任何问题。
我面临的问题是尝试使用“调用”功能更新区块链时。
这是我在 JAVA 端看到的堆栈跟踪
2019-07-17 23:34:41,811 INFO [http-nio-8080-exec-6] com.invincible.ngi.service.UtilityService: New channel initialized:mychannel
2019-07-17 23:34:41,812 INFO [http-nio-8080-exec-6] com.invincible.ngi.service.UtilityService: Order added to the channel:orderer.example.com
2019-07-17 23:34:41,813 INFO [http-nio-8080-exec-6] com.invincible.ngi.service.UtilityService: Peer added to the channel:peer0.org1.example.com
2019-07-17 23:34:43,570 INFO [http-nio-8080-exec-6] org.hyperledger.fabric.sdk.Channel: Channel Channel{id: 6, name: mychannel} eventThread started shutdown: false thread: null
2019-07-17 23:34:46,696 ERROR [http-nio-8080-exec-6] com.invincible.ngi.service.QueryService: org.hyperledger.fabric.sdk.exception.TransactionEventException: Received invalid transaction event. Transaction ID 753436574ea481148f9d2da7d793f0ff1630c0c4b3106995240cf8b73aa1f1db status 10
java.util.concurrent.ExecutionException: org.hyperledger.fabric.sdk.exception.TransactionEventException: Received invalid transaction event. Transaction ID 753436574ea481148f9d2da7d793f0ff1630c0c4b3106995240cf8b73aa1f1db status 10
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.invincible.ngi.service.QueryService.updateBlockChain(QueryService.java:56)
at com.invincible.ngi.resource.QueryResource.updateQuery(QueryResource.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.hyperledger.fabric.sdk.exception.TransactionEventException: Received invalid transaction event. Transaction ID 753436574ea481148f9d2da7d793f0ff1630c0c4b3106995240cf8b73aa1f1db status 10
at org.hyperledger.fabric.sdk.Channel$TL.lambda$fire$2(Channel.java:6227)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
... 1 common frames omitted
2019-07-17 23:34:46,703 ERROR [http-nio-8080-exec-6] org.apache.juli.logging.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [/api] threw exception [Request processing failed; nested exception is java.util.concurrent.ExecutionException: org.hyperledger.fabric.sdk.exception.TransactionEventException: Received invalid transaction event. Transaction ID 753436574ea481148f9d2da7d793f0ff1630c0c4b3106995240cf8b73aa1f1db status 10] with root cause
org.hyperledger.fabric.sdk.exception.TransactionEventException: Received invalid transaction event. Transaction ID 753436574ea481148f9d2da7d793f0ff1630c0c4b3106995240cf8b73aa1f1db status 10
at org.hyperledger.fabric.sdk.Channel$TL.lambda$fire$2(Channel.java:6227)
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)
这就是每个对等节点中出现的内容
在调查中,我发现这个问题是有效的,因为背书期望交易由每个组织的至少一个同行签署。这就是我初始化频道的方式。
Channel channel = client.newChannel(ngiProperties.getChannel());
logger.info("New channel initialized:" + ngiProperties.getChannel());
Properties ordererProperties = new Properties();
ordererProperties.setProperty("pemFile", ngiProperties.getOrdererServerCert());
ordererProperties.setProperty("trustServerCertificate", ngiProperties.getOrdererTrustServerCertificate());
ordererProperties.setProperty("hostnameOverride", ngiProperties.getOrdererHostnameOverride());
ordererProperties.setProperty("sslProvider", ngiProperties.getOrdererSslProvider());
ordererProperties.setProperty("negotiationType", ngiProperties.getOrdererNegotiationType());
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[]{ngiProperties.getOrdererKeepAliveTime(), TimeUnit.MINUTES});
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[]{ngiProperties.getOrdererKeepAliveTimeout(), TimeUnit.SECONDS});
channel.addOrderer(client.newOrderer(ngiProperties.getOrdererHost(), ngiProperties.getOrdererGrpc(), ordererProperties));
logger.info("Order added to the channel:" + ngiProperties.getOrdererHost()); // orderer.example.com
Properties peerProperties = new Properties();
peerProperties.setProperty("pemFile", ngiProperties.getPeerAServerCert());
peerProperties.setProperty("trustServerCertificate", ngiProperties.getPeerATrustServerCertificate());
peerProperties.setProperty("hostnameOverride", ngiProperties.getPeerAHostnameOverride());
peerProperties.setProperty("sslProvider", ngiProperties.getPeerASslProvider());
peerProperties.setProperty("negotiationType", ngiProperties.getPeerANegotiationType());
channel.addPeer(client.newPeer(ngiProperties.getPeerAHost(), ngiProperties.getPeerAGrpc(), peerProperties));
logger.info("Peer added to the channel:" + ngiProperties.getPeerAHost()); // peer0.org1.example.com
channel.initialize();
现在我意识到,如果只是在通道中添加来自 org2 的另一个对等点,问题就会得到解决,即,只需在初始化通道之前添加下面的代码
peerProperties = new Properties();
peerProperties.setProperty("pemFile", ngiProperties.getPeerCServerCert());
peerProperties.setProperty("trustServerCertificate", ngiProperties.getPeerCTrustServerCertificate());
peerProperties.setProperty("hostnameOverride", ngiProperties.getPeerCHostnameOverride());
peerProperties.setProperty("sslProvider", ngiProperties.getPeerCSslProvider());
peerProperties.setProperty("negotiationType", ngiProperties.getPeerCNegotiationType());
channel.addPeer(client.newPeer(ngiProperties.getPeerCHost(), ngiProperties.getPeerCGrpc(), peerProperties));
logger.info("Peer added to the channel:" + ngiProperties.getPeerCHost()); // peer0.org2.example.com
有了这个,我有几个问题
- 如果仅通过在通道初始化中添加所需的背书节点来实现交易的有效性,那么执行背书规则的意义何在?如果 org1 以某种方式设法获取 org2 的对等详细信息,那么 org1 是否可以在未经 org2 同意的情况下提交事务?
- 设置向 HFClient 提交交易的用户有什么意义?在交易过程中,用户上下文及其注册在哪里以及如何由结构验证?
- 理想情况下,我希望如果我有
AND ('Org1MSP.peer','Org2MSP.peer')
背书策略并且有一个 UI 来提交交易,在 HFClient 中设置的用户上下文应该具有“Org1MSP.peer”签名,并且 org2 中具有“Org2MSP.peer”的用户应该得到通知提交的交易。仅当具有签名“Org2MSP.peer”的任何用户签名时才应提交事务。无论我使用多少对等方来初始化通道,所有这些都应该发生。我的期望有效吗?如果是这样如何用fabric JAVA SDK实现它?