private static void sendTransactionsToListener(
     StoredBlock block,
     NewBlockType blockType,
     BlockChainListener listener,
     int relativityOffset,
     List<Transaction> transactions,
     boolean clone,
     Set<Sha256Hash> falsePositives)
     throws VerificationException {
   for (Transaction tx : transactions) {
     try {
       if (listener.isTransactionRelevant(tx)) {
         falsePositives.remove(tx.getHash());
         if (clone) tx = new Transaction(tx.params, tx.bitcoinSerialize());
         listener.receiveFromBlock(tx, block, blockType, relativityOffset++);
       }
     } catch (ScriptException e) {
       // We don't want scripts we don't understand to break the block chain so just note that this
       // tx was
       // not scanned here and continue.
       log.warn("Failed to parse a script: " + e.toString());
     } catch (ProtocolException e) {
       // Failed to duplicate tx, should never happen.
       throw new RuntimeException(e);
     }
   }
 }
 private static void informListenerForNewTransactions(
     Block block,
     NewBlockType newBlockType,
     @Nullable List<Sha256Hash> filteredTxHashList,
     @Nullable Map<Sha256Hash, Transaction> filteredTxn,
     StoredBlock newStoredBlock,
     boolean first,
     BlockChainListener listener,
     Set<Sha256Hash> falsePositives)
     throws VerificationException {
   if (block.transactions != null) {
     // If this is not the first wallet, ask for the transactions to be duplicated before being
     // given
     // to the wallet when relevant. This ensures that if we have two connected wallets and a tx
     // that
     // is relevant to both of them, they don't end up accidentally sharing the same object (which
     // can
     // result in temporary in-memory corruption during re-orgs). See bug 257. We only duplicate in
     // the case of multiple wallets to avoid an unnecessary efficiency hit in the common case.
     sendTransactionsToListener(
         newStoredBlock, newBlockType, listener, 0, block.transactions, !first, falsePositives);
   } else if (filteredTxHashList != null) {
     checkNotNull(filteredTxn);
     // We must send transactions to listeners in the order they appeared in the block - thus we
     // iterate over the
     // set of hashes and call sendTransactionsToListener with individual txn when they have not
     // already been
     // seen in loose broadcasts - otherwise notifyTransactionIsInBlock on the hash.
     int relativityOffset = 0;
     for (Sha256Hash hash : filteredTxHashList) {
       Transaction tx = filteredTxn.get(hash);
       if (tx != null) {
         sendTransactionsToListener(
             newStoredBlock,
             newBlockType,
             listener,
             relativityOffset,
             Collections.singletonList(tx),
             !first,
             falsePositives);
       } else {
         if (listener.notifyTransactionIsInBlock(
             hash, newStoredBlock, newBlockType, relativityOffset)) {
           falsePositives.remove(hash);
         }
       }
       relativityOffset++;
     }
   }
 }