如何使用Sawtooth Java SDK创建频道事件?

时间:2019-06-11 05:55:53

标签: java events hyperledger-sawtooth

HyperLeger锯齿支持在事务处理器中订阅事件。但是,有一种方法可以在事务处理器中创建特定于应用程序的事件,类似于此处的Python示例:https://www.jacklllll.xyz/blog/2019/04/08/sawtooth/

ctx.addEvent(
 'agreement/create',
 [['name', 'agreement'],
 ['address', address], 
 ['buyer name', agreement.BuyerName], 
 ['seller name', agreement.SellerName], 
 ['house id', agreement.HouseID], 
 ['creator', signer]],
  null)

在当前的Sawtooth-Java SDK v0.1.2中,唯一的替代方法是

apply(TpProcessRequest, State)

没有上下文。但是,在这里的文档中:https://github.com/hyperledger/sawtooth-sdk-java/blob/master/sawtooth-sdk-transaction-processor/src/main/java/sawtooth/sdk/processor/TransactionHandler.java

addEvent(TpProcessRequest, Context)

到目前为止,我已经设法监听了事件sawtooth/state-delta,但是这给了我tx-family的所有状态更改

import sawtooth.sdk.protobuf.EventSubscription;
import sawtooth.sdk.protobuf.EventFilter;
import sawtooth.sdk.protobuf.ClientEventsSubscribeRequest;
import sawtooth.sdk.protobuf.ClientEventsSubscribeResponse;
import sawtooth.sdk.protobuf.ClientEventsUnsubscribeRequest;
import sawtooth.sdk.protobuf.Message;

EventFilter filter = EventFilter.newBuilder()
                     .setKey("address")
                     .setMatchString(nameSpace.concat(".*"))
                     .setFilterType(EventFilter.FilterType.REGEX_ANY)
                     .build();

EventSubscription subscription = EventSubscription.newBuilder()
                      .setEventType("sawtooth/state-delta")
                      .addFilters(filter)
                      .build();

context = new ZContext();
socket = context.createSocket(ZMQ.DEALER);
socket.connect("tcp://sawtooth-rest:4004");

ClientEventsSubscribeRequest request = ClientEventsSubscribeRequest.newBuilder()
               .addSubscriptions(subscription)
               .build();

message = Message.newBuilder()
          .setCorrelationId("123")
           .setMessageType(Message.MessageType.CLIENT_EVENTS_SUBSCRIBE_REQUEST)
          .setContent(request.toByteString())
          .build();

socket.send(message.toByteArray());

Message.MessageType.CLIENT_EVENTS_SUBSCRIBE_REQUEST一旦注册,我就会在线程循环中收到消息。

我希望在TransactionHandler中能够addEvent()或创建某种类型的事件,然后可以使用Java SDK进行订阅。

还有其他人尝试过在Sawtooth上的JAVA中创建自定义事件吗?

2 个答案:

答案 0 :(得分:0)

这是在Python中添加事件的示例。 Java将是类似的。 您可以在交易处理器中添加自定义事件:

context.add_event(event_type="cookiejar/bake", attributes=[("cookies-baked", amount)])

请参见https://github.com/danintel/sawtooth-cookiejar/blob/master/pyprocessor/cookiejar_tp.py#L138

以下是用Python和Go编写的事件处理程序的示例: https://github.com/danintel/sawtooth-cookiejar/tree/master/events Java也将类似。基本上,事件处理程序中的逻辑是:

  1. 订阅要收听的事件
  2. 将请求发送到验证器
  3. 读取并解析订阅响应
  4. 在循环中,循环收听已订阅的事件
  5. 退出循环后(如果有的话),退订rom事件

答案 1 :(得分:0)

对于那些尝试使用 java SDK 进行事件发布/订阅的人 - 没有可用的直接 API。至少我找不到它,我正在使用 1.0 docker 图像。 因此,要发布您的事件,您需要直接发布到锯齿形 rest-api 服务器。需要注意以下几点:

  1. 您需要一个仅对每个请求有效的上下文 ID。您可以从 apply() 方法中的请求中获取此信息。 (代码如下)。因此,请确保您在交易发布期间发布事件,即在 apply() 方法的实施期间
  2. 事件结构将如文档 here
  3. 中所述
  4. 如果交易成功并且区块被提交,您会在事件订阅者中获得该事件,否则它不会显示。
  5. 在创建订阅者时,您需要订阅
<块引用>

锯齿/块提交

事件并为您的事件类型添加额外的订阅,例如“我的NS/我的事件”

示例事件发布代码:

public void apply(TpProcessRequest request, State state) throws InvalidTransactionException, InternalError {

       ///process your trasaction first

        sawtooth.sdk.messaging.Stream eventStream = new Stream("tcp://localhost:4004"); // make this in the constructor of class NOT here
        List<Attribute> attrList = new ArrayList<>();
        Attribute attrs = Attribute.newBuilder().setKey("someKey").setValue("someValue").build();

        attrList.add(attrs);

        Event appEvent = Event.newBuilder().setEventType("myNS/my-event-type")
                .setData( <some ByteString here>).addAllAttributes(attrList).build();
        TpEventAddRequest addEventRequest = TpEventAddRequest.newBuilder()
                .setContextId(request.getContextId()).setEvent(appEvent).build();
        Future sawtoothSubsFuture = eventStream.send(MessageType.TP_EVENT_ADD_REQUEST, addEventRequest.toByteString());

        try {
            System.out.println(sawtoothSubsFuture.getResult());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

然后你订阅这样的事件(灵感来自市场样本):

try {
            
            
            EventFilter eventFilter = EventFilter.newBuilder().setKey("address")
                    .setMatchString(String.format("^%s.*", "myNamespace"))
                    .setFilterType(FilterType.REGEX_ANY).build();

            //subscribe to sawtooth/block-commit
            EventSubscription deltaSubscription = EventSubscription.newBuilder().setEventType("sawtooth/block-commit")
                    .addFilters(eventFilter)
                    .build();

            EventSubscription mySubscription = EventSubscription.newBuilder().setEventType("myNS/my-event-type")
                    .build(); //no filters added for my events.
            
            ClientEventsSubscribeRequest subsReq = ClientEventsSubscribeRequest.newBuilder()
                    .addLastKnownBlockIds("0000000000000000").addSubscriptions(deltaSubscription).addSubscriptions(mySubscription)
                    .build();

            Future sawtoothSubsFuture = eventStream.send(MessageType.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
                    subsReq.toByteString());

            ClientEventsSubscribeResponse eventSubsResp = ClientEventsSubscribeResponse
                    .parseFrom(sawtoothSubsFuture.getResult());

            System.out.println("eventSubsResp.getStatus() :: " + eventSubsResp.getStatus());
            
             if (eventSubsResp.getStatus().equals(ClientEventsSubscribeResponse.Status.UNKNOWN_BLOCK)) {
                 System.out.println("Unknown block ");
                 // retry connection if this happens by calling this same method
                 
             }
            if(!eventSubsResp.getStatus().equals(ClientEventsSubscribeResponse.Status.OK)) {
                System.out.println("Subscription failed with status " + eventSubsResp.getStatus());
                throw new RuntimeException("cannot connect ");
            } else {
                isActive = true;
                System.out.println("Making active ");
            }
            
            
            while(isActive) {
                Message eventMsg =  eventStream.receive();
                EventList eventList = EventList.parseFrom(eventMsg.getContent());
                for (Event event : eventList.getEventsList()) {                 
                    System.out.println("An event ::::");
                    System.out.println(event);
                }
                
            }
        } catch (Exception e) {
            e.printStackTrace();
        }