[翻译] Hyperledger Fabric Java SDK上的Chaincode Event监听器教程

原文地址: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

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 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 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 successful = new LinkedList<>();
    Collection failed = new LinkedList<>();

    // START CHAINCODE EVENT LISTENER HANDLER----------------------
    String expectedEventName = "AgentCreatedEvent";
    Vector chaincodeEvents = new Vector<>(); // Test list to capture
    String chaincodeEventListenerHandle =
        SdkIntegration.setChaincodeEventListener(channel, expectedEventName, chaincodeEvents);
    // END CHAINCODE EVENT LISTENER HANDLER------------------------

    Collection 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 chaincodeEvents = new Vector <>();)然后我们创建ChaincodeEventListener,调用之前定义的函数(setChaincodeEventListener)。(
将(成功的)事务提议发送到Orderer之后 - 在这部分我们等待调用函数waitForChaincodeEvent在这里显示的 Event,它基本上是一个超时的orderer:

public static boolean waitForChaincodeEvent(Integer timeout, Channel channel,
    Vector 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上的Chaincode Event监听器教程)