@Override
 public Transaction newTransaction(
     short deadline,
     byte[] senderPublicKey,
     Long recipientId,
     long amountNQT,
     long feeNQT,
     String referencedTransactionFullHash,
     Attachment attachment)
     throws NxtException.ValidationException {
   TransactionImpl transaction =
       new TransactionImpl(
           attachment.getTransactionType(),
           Convert.getEpochTime(),
           deadline,
           senderPublicKey,
           recipientId,
           amountNQT,
           feeNQT,
           referencedTransactionFullHash,
           null);
   transaction.setAttachment(attachment);
   transaction.validateAttachment();
   return transaction;
 }
        @Override
        public void run() {

          try {
            try {
              List<Transaction> transactionList = new ArrayList<>();
              int curTime = Convert.getEpochTime();
              for (TransactionImpl transaction : nonBroadcastedTransactions.values()) {
                if (TransactionDb.hasTransaction(transaction.getId())
                    || transaction.getExpiration() < curTime) {
                  nonBroadcastedTransactions.remove(transaction.getId());
                } else if (transaction.getTimestamp() < curTime - 30) {
                  transactionList.add(transaction);
                }
              }

              if (transactionList.size() > 0) {
                Peers.sendToSomePeers(transactionList);
              }

            } catch (Exception e) {
              Logger.logDebugMessage("Error in transaction re-broadcasting thread", e);
            }
          } catch (Throwable t) {
            Logger.logMessage("CRITICAL ERROR. PLEASE REPORT TO THE DEVELOPERS.\n" + t.toString());
            t.printStackTrace();
            System.exit(1);
          }
        }
        @Override
        public void run() {

          try {
            try {

              int curTime = Convert.getEpochTime();
              List<Transaction> removedUnconfirmedTransactions = new ArrayList<>();

              synchronized (BlockchainImpl.getInstance()) {
                Iterator<TransactionImpl> iterator = unconfirmedTransactions.values().iterator();
                while (iterator.hasNext()) {
                  TransactionImpl transaction = iterator.next();
                  if (transaction.getExpiration() < curTime) {
                    iterator.remove();
                    unconfirmedTransactionHashes.remove(transaction.getHash());
                    transaction.undoUnconfirmed();
                    removedUnconfirmedTransactions.add(transaction);
                  }
                }
              }

              if (removedUnconfirmedTransactions.size() > 0) {
                transactionListeners.notify(
                    removedUnconfirmedTransactions, Event.REMOVED_UNCONFIRMED_TRANSACTIONS);
              }

            } catch (Exception e) {
              Logger.logDebugMessage("Error removing unconfirmed transactions", e);
            }
          } catch (Throwable t) {
            Logger.logMessage("CRITICAL ERROR. PLEASE REPORT TO THE DEVELOPERS.\n" + t.toString());
            t.printStackTrace();
            System.exit(1);
          }
        }
  private List<Transaction> processTransactions(
      List<TransactionImpl> transactions, final boolean sendToPeers) {
    List<Transaction> sendToPeersTransactions = new ArrayList<>();
    List<Transaction> addedUnconfirmedTransactions = new ArrayList<>();
    List<Transaction> addedDoubleSpendingTransactions = new ArrayList<>();

    for (TransactionImpl transaction : transactions) {

      try {

        int curTime = Convert.getEpochTime();
        if (transaction.getTimestamp() > curTime + 15
            || transaction.getExpiration() < curTime
            || transaction.getDeadline() > 1440) {
          continue;
        }

        synchronized (BlockchainImpl.getInstance()) {
          Long id = transaction.getId();
          if (TransactionDb.hasTransaction(id)
              || unconfirmedTransactions.containsKey(id)
              || !transaction.verify()) {
            continue;
          }

          if (transactionHashes.containsKey(transaction.getHash())
              || unconfirmedTransactionHashes.containsKey(transaction.getHash())) {
            continue;
          }

          if (transaction.applyUnconfirmed()) {
            if (sendToPeers) {
              if (nonBroadcastedTransactions.containsKey(id)) {
                Logger.logDebugMessage(
                    "Received back transaction "
                        + transaction.getStringId()
                        + " that we generated, will not forward to peers");
                nonBroadcastedTransactions.remove(id);
              } else {
                sendToPeersTransactions.add(transaction);
              }
            }
            unconfirmedTransactions.put(id, transaction);
            unconfirmedTransactionHashes.put(transaction.getHash(), transaction);
            addedUnconfirmedTransactions.add(transaction);
          } else {
            addedDoubleSpendingTransactions.add(transaction);
          }
        }

      } catch (RuntimeException e) {
        Logger.logMessage("Error processing transaction", e);
      }
    }

    if (sendToPeersTransactions.size() > 0) {
      Peers.sendToSomePeers(sendToPeersTransactions);
    }

    if (addedUnconfirmedTransactions.size() > 0) {
      transactionListeners.notify(
          addedUnconfirmedTransactions, Event.ADDED_UNCONFIRMED_TRANSACTIONS);
    }
    if (addedDoubleSpendingTransactions.size() > 0) {
      transactionListeners.notify(
          addedDoubleSpendingTransactions, Event.ADDED_DOUBLESPENDING_TRANSACTIONS);
    }
    return addedUnconfirmedTransactions;
  }