Я использую пример первой сети Ткань Hyperledger v1.4 для настройки сети блокчейна с двумя организациями и четырьмя одноранговыми узлами. Здесь — это скриншот процессов 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
В связи с этим у меня есть несколько вопросов
AND ('Org1MSP.peer','Org2MSP.peer')
в качестве политики подтверждения и есть пользовательский интерфейс для отправки транзакции, пользовательский контекст, установленный в HFClient, должен иметь подпись «Org1MSP.peer», а пользователи в org2 с «Org2MSP.peer» должны быть уведомлены. о представленной транзакции. Транзакция должна быть зафиксирована только тогда, когда любой пользователь с подписью «Org2MSP.peer» подписывает ее. И все это должно происходить независимо от того, сколько пиров я использовал для инициализации канала. Справедливо ли мое ожидание? Если да, то как этого добиться с помощью Fabric JAVA SDK?If the validity of a transaction is achieved just by adding the required endorsing peers in the channel initialisation, what is the point of enforcing endorsement rule? If org1 somehow manages to get the peer details of of org2, org1 can commit transactions without having consent from org2?
Одобряющие пиры — это пиры, на которых установлены чейнкоды.
Теперь, когда ваш клиент отправляет предложение о транзакции для
Подтверждение. Сначала он проверяет политику подтверждения во время выполнения структуры. в вашем случае это
был AND('Org1MSP.peer','Org2MSP.peer')
, что означает оба
индоссанты должны вернуть ответ на предложение, но у вас был только один
вглядываться в канал, поэтому он терпит неудачу на самом 1-м шаге, где он
не соответствует правилу политики одобрения.
** Применение политики одобрения позволяет управлять фальсификацией данных, а также одним узлом и двойной тратой. ** Очень
подробный обзор здесь.
Поскольку сеть будет распределенной, вряд ли какая-либо организация сможет получить доступ к сертификатам любой другой организации.
P.S. Подписание транзакций — это автоматизированный процесс, ни в одной организации не будет людей, которые будут подписывать транзакции вручную.
Надеюсь это поможет.
And what is the point of setting the user who is submitting the transaction to the HFClient? Where and how that user context and its enrolment validated by fabric in the transaction process?
Чтобы узнать, кто хочет изменить состояние данных в блокчейне. Например, когда org1 хочет изменить право собственности на автомобиль, тогда, когда данные будут зафиксированы, когда будет известно, кто изменил право собственности на автомобиль.
Ideally I would expect if I have AND ('Org1MSP.peer','Org2MSP.peer') as endorsement policy and have an UI to submit the transaction, the user context set in the HFClient should have the 'Org1MSP.peer' signature and the users in org2 with 'Org2MSP.peer' should get notified about the transation submitted. The transaction should be committed only when any user with signature 'Org2MSP.peer' signs it. And all these should happen irrespective of how many peers I have used to initialise the channel. Is my expectation valid? If so how to achieve it with fabric JAVA SDK?
ну, клиент просто отправляет предложение о транзакции, т.е. операцию, которая должна быть выполнена, и метаданные для нее, и подписывает ее своим закрытым ключом. Контейнеры чейнкода будут заботиться о своих собственных сертификатах. На самом деле нет человека, который бы вручную подписывал транзакцию. предложение, это автоматизировано процесс, выполняемый поддерживающим партнером.