美文网首页
[翻译] Hyperledger Fabric Java SDK

[翻译] Hyperledger Fabric Java SDK

作者: 淸_兲鮭鮭 | 来源:发表于2019-11-08 16:38 被阅读0次

    原文地址:https://medium.com/coinmonks/tutorial-chaincode-event-listener-on-hyperledger-fabric-java-sdk-557304f1fe28

    自己跟着教程做了一遍,可以达到自己想实现的效果,监听到链码中的event。

    Hyperledger Fabric Java SDK上的Chaincode Event监听器教程

    Valerio Mattioli

    嗨,大家好!本教程适用于已经具备fabric-sdk-java经验的所有Java开发人员。今天,我想向您展示如何设置“Chaincode Event监听器”,以准确了解提交的事务何时最终在区块链中提交,如图中所述的工作流程。

    在进入代码之前,我给出了 Event的定义: Event是如何将结构与不同系统集成的主要方式。因此,您可以理解掌握 Event创建,聆听和处理的重要性。

    Hyperledger Fabric中的开发人员交互

    前提条件是系统已经运行,正如Lukas Kolisko本教程中所解释的那样。

    在您拥有可以从Java SDK调用的工作链代码的基本系统之后,您可以开始在代码中包含event。

    我们需要修改,创建或实现的文件按顺序:

    chaincode -我们需要“PutState”与后设置从chaincode eventshim.ChaincodeStubInterface.SetEvent

    ChaincodeEventCapture - 我们需要创建这个类来捕获chaincode event。

    chaincodeEvents - 它是列表,恰好是当event来自链码时填充的Vector <ChaincodeEventCapture>。

    ChaincodeEventListener - 这是我们需要实现接收链代码event的接口。

    在链码中设置event(发出event)

    这部分是最简单的一个过程(是的,谢谢Go!),你基本上必须在PutState之后立即添加SetEvent以让链代码发出event。有关活动的所有事情都在本视频中得到了很好的解释。

    现在重要的是要知道每个事务只能设置一个event(只有最后一个SetEvent会被转移回SDK)

    image.jpeg

    我展示了一个代码示例,您可以从此repo中找到。

    // tSet event 在chaincodehis 调用之后执行一些检查后的PutState
    agent := a.CreateAgent(agentId, agentName, agentAddress, stub)  
    
    // ====代理已保存。Set Event ===
    eventPayload:="Created Agent: " + agentId
    payloadAsBytes := []byte(eventPayload)
    eventError := stub.SetEvent("AgentCreatedEvent",payloadAsBytes)
    

    添加这3行代码,我们已经完成了从链代码部分发出的 Event音乐会,现在让我们跳转到Java客户端应用程序 - SDK部分!

    创建ChaincodeEventCapture类

    现在是时候创建类来捕获链代码 Event了,我从fabric-sdk官方测试的测试端到端方案中学习了这种方法。

    public class ChaincodeEventCapture { 
      private final String handle;
      private final BlockEvent blockEvent;
      private final ChaincodeEvent chaincodeEvent;
    
      public ChaincodeEventCapture(String handle, BlockEvent blockEvent,
          ChaincodeEvent chaincodeEvent) {
        this.handle = handle;
        this.blockEvent = blockEvent;
        this.chaincodeEvent = chaincodeEvent;
      }
    
      /**
       * @return the handle
       */
      public String getHandle() {
        return handle;
      }
    
      /**
       * @return the blockEvent
       */
      public BlockEvent getBlockEvent() {
        return blockEvent;
      }
    
      /**
       * @return the chaincodeEvent
       */
      public ChaincodeEvent getChaincodeEvent() {
        return chaincodeEvent;
      }
    }
    

    创建ChaincodeEventCapture列表

    这个列表是这个方法的核心,因为它将填充监听器捕获的 Event。

    Vector<ChaincodeEventCapture> chaincodeEvents = new Vector<>();
    

    实现Chaincode Event监听器

    这个列表是这个方法的核心,因为它将填充监听器捕获的 Event。这里的接口声明

    ChaincodeEventListener chaincodeEventListener = new ChaincodeEventListener() {
    
        @Override
        public void received(String handle, BlockEvent blockEvent,     ChaincodeEvent chaincodeEvent) {
            chaincodeEvents.add(new ChaincodeEventCapture(handle, blockEvent, chaincodeEvent));
    
            String eventHub = blockEvent.getPeer();
    if(eventHub != null){ 
                eventHub = blockEvent.getPeer().getName()
            } else {
                eventHub = blockEvent.getEventHub().getName();
            }
            // Here put what you want to do when receive chaincode event
            System.out.println("RECEIVED CHAINCODE EVENT with handle: " + handle + ", chaincodeId: " + chaincodeEvent.getChaincodeId() + ", chaincode event name: " + chaincodeEvent.getEventName() + ", transactionId: " + chaincodeEvent.getTxId() +", event Payload: " + new String(chaincodeEvent.getPayload()) + ", from eventHub: " + eventHub));
        }
    };
    

    让我们把所有东西放在一起!

    首先,在我的实现中,我创建了封装的方法 ChaincodeEventListener实现 和他的注册:

    public static String setChaincodeEventListener(Channel channel,
        String expectedEventName, Vector<ChaincodeEventCapture> chaincodeEvents)
        throws InvalidArgumentException {
    
        ChaincodeEventListener chaincodeEventListener = new ChaincodeEventListener() {
    
            @Override public void received(String handle, BlockEvent blockEvent,
                ChaincodeEvent chaincodeEvent) {// ...the code up...}
        };
        // chaincode events.
        String eventListenerHandle = channel.registerChaincodeEventListener(Pattern.compile(".*"),
            Pattern.compile(Pattern.quote(expectedEventName)), chaincodeEventListener);
        return eventListenerHandle;
    }
    

    其次,我们转到对chaincode的调用,因为您已经开始阅读本文并添加 Event处理部分。

    public boolean createAgent(HFClient clientHF, User userHF, Channel channel, Agent newAgent)
        throws ProposalException, InvalidArgumentException {
    
        String chaincodeFunctionName = "CreateAgent";
    
        String agentId = newAgent.getAgentId().toString();
        String agentName = newAgent.getName().toString();
        String agentAddress = newAgent.getAddress().toString();
    
        String[] chaincodeArguments = new String[] {agentId, agentName, agentAddress};
    
        Collection<ProposalResponse> successful = new LinkedList<>();
        Collection<ProposalResponse> failed = new LinkedList<>();
    
        // START CHAINCODE EVENT LISTENER HANDLER----------------------
        String expectedEventName = "AgentCreatedEvent";
        Vector<ChaincodeEventCapture> chaincodeEvents = new Vector<>(); // Test list to capture
        String chaincodeEventListenerHandle =
            SdkIntegration.setChaincodeEventListener(channel, expectedEventName, chaincodeEvents);
        // END CHAINCODE EVENT LISTENER HANDLER------------------------
    
        Collection<ProposalResponse> invokePropResp =
            writeBlockchain(clientHF, userHF, channel, chaincodeName, chaincodeFunctionName,
                chaincodeArguments);
    
        boolean allPeerSucces = printWriteProposalResponse(successful, failed, invokePropResp);
    
        System.out.println("successfully received transaction proposal responses.");
    
        /**
         * Send transaction to orderer only if all peer success
         */
    
        sendTxToOrderer(userHF, channel, successful, allPeerSucces);
    
        // START WAIT FOR THE EVENT-------------------------------------
        boolean eventDone = false;
        eventDone = SdkIntegration
            .waitForChaincodeEvent(150, channel, chaincodeEvents, chaincodeEventListenerHandle);
        log.info("eventDone: " + eventDone);
        // END WAIT FOR THE EVENT---------------------------------------
        return allPeerSucces;
    
    }
    

    正如你在上面的代码中所说,我们在调用中添加了两个部分(在注释中突出显示了开始和结尾以及尾随行:
    在区块链中写入之前 - 我们首先创建将由eventListener填充 Event的空列表(Vector <ChaincodeEventCapture> chaincodeEvents = new Vector <>();)然后我们创建ChaincodeEventListener,调用之前定义的函数(setChaincodeEventListener)。(
    将(成功的)事务提议发送到Orderer之后 - 在这部分我们等待调用函数waitForChaincodeEvent在这里显示的 Event,它基本上是一个超时的orderer:

    public static boolean waitForChaincodeEvent(Integer timeout, Channel channel,
        Vector<ChaincodeEventCapture> chaincodeEvents, String chaincodeEventListenerHandle)
        throws InvalidArgumentException {
        boolean eventDone = false;
        if (chaincodeEventListenerHandle != null) {
    
    
            int numberEventsExpected = channel.getEventHubs().size() + channel
                .getPeers(EnumSet.of(Peer.PeerRole.EVENT_SOURCE)).size();
            log.info("numberEventsExpected: " + numberEventsExpected);
            //just make sure we get the notifications
            if (timeout.equals(0)) {
                // get event without timer
                while (chaincodeEvents.size() != numberEventsExpected) {
                    // do nothing
                }
                eventDone = true;
            } else {
                // get event with timer
                for (int i = 0; i < timeout; i++) {
                    if (chaincodeEvents.size() == numberEventsExpected) {
                        eventDone = true;
                        break;
                    } else {
                        try {
                            double j = i;
                            j = j / 10;
                            log.info(j + " second");
                            Thread.sleep(100); // wait for the events for one tenth of second.
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
    
            log.info("chaincodeEvents.size(): " + chaincodeEvents.size());
    
            // unregister event listener
            channel.unregisterChaincodeEventListener(chaincodeEventListenerHandle);
            int i = 1;
            // arrived event handling
            for (ChaincodeEventCapture chaincodeEventCapture : chaincodeEvents) {
                log.info("Event number. " + i);
                log.info("event capture object: " + chaincodeEventCapture.toString());
                log.info("Event Handle: " + chaincodeEventCapture.getHandle());
                log.info("Event TxId: " + chaincodeEventCapture.getChaincodeEvent().getTxId());
                log.info("Event Name: " + chaincodeEventCapture.getChaincodeEvent().getEventName());
                log.info("Event Payload: " + chaincodeEventCapture.getChaincodeEvent()
                    .getPayload()); // byte
                log.info("Event ChaincodeId: " + chaincodeEventCapture.getChaincodeEvent()
                    .getChaincodeId());
                BlockEvent blockEvent = chaincodeEventCapture.getBlockEvent();
                try {
                    log.info("Event Channel: " + blockEvent.getChannelId());
                } catch (InvalidProtocolBufferException e) {
                    e.printStackTrace();
                }
                log.info("Event Hub: " + blockEvent.getEventHub());
              
                i++;
            }
    
        } else {
            log.info("chaincodeEvents.isEmpty(): " + chaincodeEvents.isEmpty());
        }
        log.info("eventDone: " + eventDone);
        return eventDone;
    }
    

    如果你想要,为简单起见,首先测试 Event处理的工作,你可以用这个空的替换这个最后的函数(waitForChaincodeEvent)(我不推荐):

            while (chaincodeEvents.isEmpty()) {
                // do nothing
            }
    

    现在我们已经完成了!您正在处理hyperledger-fabric Java SDK上的chaincode Event!

    我希望本教程有用!如果是,请不要犹豫,给我一个响亮的鼓掌!;)

    再见!

    • Valerio

    相关文章

      网友评论

          本文标题:[翻译] Hyperledger Fabric Java SDK

          本文链接:https://www.haomeiwen.com/subject/ivzfyctx.html