@Override
  public APIBlockIdList getBlockIds(BID blockId, int count) throws BCSAPIException {
    try (ConnectorSession session = connection.createSession()) {
      log.trace("get " + count + " block ids from " + blockId);

      ConnectorProducer blockIdsRequestProducer =
          session.createProducer(session.createQueue("blockIdsRequest"));

      ConnectorMessage m = session.createMessage();
      BCSAPIMessage.BLKIDSREQ.Builder builder = BCSAPIMessage.BLKIDSREQ.newBuilder();
      if (blockId != null) {
        builder.setBlockHash(ByteString.copyFrom(blockId.unsafeGetArray()));
      }
      if (count <= 0) count = 20;
      builder.setCount(count);
      m.setPayload(builder.build().toByteArray());
      byte[] response = synchronousRequest(session, blockIdsRequestProducer, m);
      if (response != null) {
        BCSAPIMessage.BLKIDS message = BCSAPIMessage.BLKIDS.parseFrom(response);
        List<ByteString> blockIdsList = message.getBlockIdsList();
        List<BID> blockIds =
            blockIdsList.stream().map(bs -> new BID(bs.toByteArray())).collect(Collectors.toList());
        return new APIBlockIdList(
            blockIds,
            message.getHeight(),
            message.hasPreviousBlockId()
                ? new BID(message.getPreviousBlockId().toByteArray())
                : null);
      }
    } catch (ConnectorException | InvalidProtocolBufferException e) {
      throw new BCSAPIException(e);
    }

    return null;
  }
  @Override
  public List<APITransaction> getInputTransactions(TID txId) throws BCSAPIException {
    log.trace("get input transactions " + txId);
    ConnectorMessage m;
    try (ConnectorSession session = connection.createSession()) {
      ConnectorProducer transactionRequestProducer =
          session.createProducer(session.createQueue("inputTransactionsRequest"));

      m = session.createMessage();
      BCSAPIMessage.Hash.Builder builder = BCSAPIMessage.Hash.newBuilder();
      builder.addHash(ByteString.copyFrom(txId.unsafeGetArray()));
      m.setPayload(builder.build().toByteArray());
      byte[] response = synchronousRequest(session, transactionRequestProducer, m);
      if (response != null) {
        List<BCSAPIMessage.OPTIONAL_TX> txsList =
            BCSAPIMessage.TXS.parseFrom(response).getTxsList();
        List<APITransaction> txs = new ArrayList<>(txsList.size());
        for (BCSAPIMessage.OPTIONAL_TX tx : txsList) {
          if (tx.getIsNull()) {
            txs.add(null);
          } else {
            txs.add(APITransaction.fromProtobuf(tx.getTransaction()));
          }
        }
        return txs;
      }
    } catch (ConnectorException | HyperLedgerException | InvalidProtocolBufferException e) {
      throw new BCSAPIException(e);
    }

    return null;
  }
  @Override
  public void catchUp(List<BID> inventory, int limit, boolean headers, final TrunkListener listener)
      throws BCSAPIException {
    log.trace("catchUp");
    ConnectorMessage m;
    try (ConnectorSession session = connection.createSession()) {
      ConnectorProducer transactionRequestProducer =
          session.createProducer(session.createQueue("catchUpRequest"));

      m = session.createMessage();
      BCSAPIMessage.CatchUpRequest.Builder builder = BCSAPIMessage.CatchUpRequest.newBuilder();
      builder.setLimit(limit);
      builder.setHeaders(true);
      for (BID hash : inventory) {
        builder.addInventory(ByteString.copyFrom(hash.unsafeGetArray()));
      }
      m.setPayload(builder.build().toByteArray());
      byte[] response = synchronousRequest(session, transactionRequestProducer, m);
      if (response != null) {
        BCSAPIMessage.TrunkUpdate blockMessage = BCSAPIMessage.TrunkUpdate.parseFrom(response);
        List<APIBlock> blockList = new ArrayList<>();
        for (BCSAPIMessage.BLK b : blockMessage.getAddedList()) {
          blockList.add(APIBlock.fromProtobuf(b));
        }
        listener.trunkUpdate(blockList);
      }
    } catch (ConnectorException | HyperLedgerException | InvalidProtocolBufferException e) {
      throw new BCSAPIException(e);
    }
  }
 @Override
 public void scanTransactionsForAddresses(Set<Address> addresses, TransactionListener listener)
     throws BCSAPIException {
   List<Script> al = new ArrayList<>(addresses.size());
   for (Address a : addresses) {
     try {
       al.add(a.getAddressScript());
     } catch (HyperLedgerException e) {
     }
   }
   scanRequest(al, listener, "matchRequest");
 }
 @Override
 public void registerTrunkListener(final TrunkListener listener) throws BCSAPIException {
   try {
     addTopicListener(
         "trunk",
         listener,
         body -> {
           List<APIBlock> blockList = null;
           try {
             BCSAPIMessage.TrunkUpdate blockMessage = BCSAPIMessage.TrunkUpdate.parseFrom(body);
             blockList = new ArrayList<>();
             for (BCSAPIMessage.BLK b : blockMessage.getAddedList()) {
               blockList.add(APIBlock.fromProtobuf(b));
             }
           } catch (Exception e) {
             log.error("Block message error", e);
           }
           return blockList;
         },
         blocks -> listener.trunkUpdate(blocks));
   } catch (ConnectorException e) {
     throw new BCSAPIException(e);
   }
 }