@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 registerTransactionListener(final TransactionListener listener)
     throws BCSAPIException {
   try {
     addTopicListener(
         "transaction",
         listener,
         bytes -> {
           APITransaction transaction = null;
           try {
             transaction = APITransaction.fromProtobuf(BCSAPIMessage.TX.parseFrom(bytes));
           } catch (Exception e) {
             log.error("Transaction message error", e);
           }
           return transaction;
         },
         transaction -> {
           if (transaction != null)
             try {
               listener.process(transaction);
             } catch (HyperLedgerException e) {
               log.error("Error in transaction processing", e);
             }
         });
   } catch (ConnectorException e) {
     throw new BCSAPIException(e);
   }
 }
  @Override
  public void spendingTransactions(List<TID> tids, final TransactionListener listener)
      throws BCSAPIException {
    try (ConnectorSession session = connection.createSession()) {
      ConnectorMessage m = session.createMessage();

      ConnectorProducer scanAccountProducer =
          session.createProducer(session.createQueue("spendingTransactions"));
      BCSAPIMessage.Hash.Builder builder = BCSAPIMessage.Hash.newBuilder();
      for (TID tid : tids) {
        builder.addHash(ByteString.copyFrom(tid.unsafeGetArray()));
      }
      m.setPayload(builder.build().toByteArray());

      final ConnectorTemporaryQueue answerQueue = session.createTemporaryQueue();
      final ConnectorConsumer consumer = session.createConsumer(answerQueue);
      m.setReplyTo(answerQueue);
      final Semaphore ready = new Semaphore(0);
      consumer.setMessageListener(
          message -> {
            try {
              byte[] body = message.getPayload();
              if (body != null) {
                APITransaction t = APITransaction.fromProtobuf(BCSAPIMessage.TX.parseFrom(body));
                listener.process(t);
              } else {
                consumer.close();
                answerQueue.delete();
                ready.release();
              }
            } catch (ConnectorException | HyperLedgerException | InvalidProtocolBufferException e) {
              log.error("Malformed message received for spendingt ransactions request", e);
            }
          });

      scanAccountProducer.send(m);
      ready.acquireUninterruptibly();
    } catch (ConnectorException e) {
      throw new BCSAPIException(e);
    }
  }
  private void scanRequest(
      Collection<Script> match, final TransactionListener listener, String requestQueue)
      throws BCSAPIException {
    try (ConnectorSession session = connection.createSession()) {
      ConnectorMessage m = session.createMessage();

      ConnectorProducer exactMatchProducer =
          session.createProducer(session.createQueue(requestQueue));
      BCSAPIMessage.ExactMatchRequest.Builder builder =
          BCSAPIMessage.ExactMatchRequest.newBuilder();
      for (Script d : match) {
        builder.addMatch(ByteString.copyFrom(d.toByteArray()));
      }
      m.setPayload(builder.build().toByteArray());
      final ConnectorTemporaryQueue answerQueue = session.createTemporaryQueue();
      final ConnectorConsumer consumer = session.createConsumer(answerQueue);
      m.setReplyTo(answerQueue);
      final Semaphore ready = new Semaphore(0);
      consumer.setMessageListener(
          message -> {
            try {
              byte[] body = message.getPayload();
              if (body != null) {
                APITransaction t = APITransaction.fromProtobuf(BCSAPIMessage.TX.parseFrom(body));
                listener.process(t);
              } else {
                consumer.close();
                answerQueue.delete();
                ready.release();
              }
            } catch (ConnectorException | HyperLedgerException | InvalidProtocolBufferException e) {
              log.error("Malformed message received for scan matching transactions", e);
            }
          });

      exactMatchProducer.send(m);
      ready.acquireUninterruptibly();
    } catch (ConnectorException e) {
      throw new BCSAPIException(e);
    }
  }
  private void scanRequest(
      MasterPublicKey master, int lookAhead, final TransactionListener listener, String request)
      throws BCSAPIException {
    try (ConnectorSession session = connection.createSession()) {
      ConnectorMessage m = session.createMessage();

      ConnectorProducer scanAccountProducer = session.createProducer(session.createQueue(request));
      BCSAPIMessage.AccountRequest.Builder builder = BCSAPIMessage.AccountRequest.newBuilder();
      builder.setPublicKey(master.serialize(true));
      builder.setLookAhead(lookAhead);
      m.setPayload(builder.build().toByteArray());

      final ConnectorTemporaryQueue answerQueue = session.createTemporaryQueue();
      final ConnectorConsumer consumer = session.createConsumer(answerQueue);
      m.setReplyTo(answerQueue);
      final Semaphore ready = new Semaphore(0);
      consumer.setMessageListener(
          message -> {
            try {
              byte[] body = message.getPayload();
              if (body != null) {
                APITransaction t = APITransaction.fromProtobuf(BCSAPIMessage.TX.parseFrom(body));
                listener.process(t);
              } else {
                consumer.close();
                answerQueue.delete();
                ready.release();
              }
            } catch (ConnectorException | HyperLedgerException | InvalidProtocolBufferException e) {
              log.error("Malformed message received for account scan transactions", e);
            }
          });

      scanAccountProducer.send(m);
      ready.acquireUninterruptibly();
    } catch (ConnectorException e) {
      throw new BCSAPIException(e);
    }
  }
  @Override
  public APITransaction getTransaction(TID hash) throws BCSAPIException {
    log.trace("get transaction " + hash);
    ConnectorMessage m;
    try (ConnectorSession session = connection.createSession()) {
      ConnectorProducer transactionRequestProducer =
          session.createProducer(session.createQueue("transactionRequest"));

      m = session.createMessage();
      BCSAPIMessage.Hash.Builder builder = BCSAPIMessage.Hash.newBuilder();
      builder.addHash(ByteString.copyFrom(hash.unsafeGetArray()));
      m.setPayload(builder.build().toByteArray());
      byte[] response = synchronousRequest(session, transactionRequestProducer, m);
      if (response != null) {
        APITransaction t;
        t = APITransaction.fromProtobuf(BCSAPIMessage.TX.parseFrom(response));
        return t;
      }
    } catch (ConnectorException | HyperLedgerException | InvalidProtocolBufferException e) {
      throw new BCSAPIException(e);
    }

    return null;
  }