Одобрение от нескольких организаций из Hyperledger Fabric JAVA SDK

Я использую пример первой сети Ткань 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

В связи с этим у меня есть несколько вопросов

  1. Если валидность транзакции достигается простым добавлением необходимых поддерживающих одноранговых узлов при инициализации канала, какой смысл применять правило подтверждения? Если org1 каким-то образом удается получить информацию об одноранговых узлах org2, может ли org1 совершать транзакции без согласия org2?
  2. И какой смысл устанавливать пользователя, который отправляет транзакцию в HFClient? Где и как этот пользовательский контекст и его регистрация проверяются структурой в процессе транзакции?
  3. В идеале я ожидаю, что если у меня есть AND ('Org1MSP.peer','Org2MSP.peer') в качестве политики подтверждения и есть пользовательский интерфейс для отправки транзакции, пользовательский контекст, установленный в HFClient, должен иметь подпись «Org1MSP.peer», а пользователи в org2 с «Org2MSP.peer» должны быть уведомлены. о представленной транзакции. Транзакция должна быть зафиксирована только тогда, когда любой пользователь с подписью «Org2MSP.peer» подписывает ее. И все это должно происходить независимо от того, сколько пиров я использовал для инициализации канала. Справедливо ли мое ожидание? Если да, то как этого добиться с помощью Fabric JAVA SDK?
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
547
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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?

  1. Одобряющие пиры — это пиры, на которых установлены чейнкоды. Теперь, когда ваш клиент отправляет предложение о транзакции для Подтверждение. Сначала он проверяет политику подтверждения во время выполнения структуры. в вашем случае это был AND('Org1MSP.peer','Org2MSP.peer'), что означает оба индоссанты должны вернуть ответ на предложение, но у вас был только один вглядываться в канал, поэтому он терпит неудачу на самом 1-м шаге, где он не соответствует правилу политики одобрения. ** Применение политики одобрения позволяет управлять фальсификацией данных, а также одним узлом и двойной тратой. ** Очень подробный обзор здесь.

  2. Поскольку сеть будет распределенной, вряд ли какая-либо организация сможет получить доступ к сертификатам любой другой организации.

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?

ну, клиент просто отправляет предложение о транзакции, т.е. операцию, которая должна быть выполнена, и метаданные для нее, и подписывает ее своим закрытым ключом. Контейнеры чейнкода будут заботиться о своих собственных сертификатах. На самом деле нет человека, который бы вручную подписывал транзакцию. предложение, это автоматизировано процесс, выполняемый поддерживающим партнером.

Другие вопросы по теме