private ValidationResult<TransactionInvalidReason> addTransaction(
      final Transaction baseTransaction, final boolean isLocal, final byte score) {

    final boolean hasPriority = isPriorityTransaction(baseTransaction, isLocal);

    if (pendingTransactions.containsTransaction(baseTransaction)) {
      LOG.atTrace()
          .setMessage("Discard already present transaction {}")
          .addArgument(baseTransaction::toTraceLog)
          .log();
      // We already have this transaction, don't even validate it.
      metrics.incrementRejected(isLocal, hasPriority, TRANSACTION_ALREADY_KNOWN, "txpool");
      return ValidationResult.invalid(TRANSACTION_ALREADY_KNOWN);
    }

    // Apply any necessary fork related pre-processing before submitting the transaction to the pool
    Transaction transaction =
        getTransactionPoolPreProcessor()
            .map(preProcessor -> preProcessor.prepareTransaction(baseTransaction, isLocal))
            .orElse(baseTransaction);

    final ValidationResultAndAccount validationResult =
        validateTransaction(transaction, isLocal, hasPriority);

    if (validationResult.result.isValid()) {
      final TransactionAddedResult status =
          pendingTransactions.addTransaction(
              PendingTransaction.newPendingTransaction(transaction, isLocal, hasPriority, score),
              validationResult.maybeAccount);
      if (status.isSuccess()) {
        LOG.atTrace()
            .setMessage("Added {} transaction {}")
            .addArgument(() -> isLocal ? "local" : "remote")
            .addArgument(transaction::toTraceLog)
            .log();
      } else {
        final var rejectReason =
            status
                .maybeInvalidReason()
                .orElseGet(
                    () -> {
                      LOG.warn("Missing invalid reason for status {}", status);
                      return INTERNAL_ERROR;
                    });
        LOG.atTrace()
            .setMessage("Transaction {} rejected reason {}")
            .addArgument(transaction::toTraceLog)
            .addArgument(rejectReason)
            .log();
        metrics.incrementRejected(isLocal, hasPriority, rejectReason, "txpool");
        return ValidationResult.invalid(rejectReason);
      }
    } else {
      LOG.atTrace()
          .setMessage("Discard invalid transaction {}, reason {}, because {}")
          .addArgument(transaction::toTraceLog)
          .addArgument(validationResult.result::getInvalidReason)
          .addArgument(validationResult.result::getErrorMessage)
          .log();
      metrics.incrementRejected(
          isLocal, hasPriority, validationResult.result.getInvalidReason(), "txpool");
    }

    return validationResult.result;
  }
Maintains the set of pending transactions received from JSON-RPC or other nodes. Transactions are
removed automatically when they are included in a block on the canonical chain and re-added if a
re-org removes them from the canonical chain again.

<p>This class is safe for use across multiple threads.
ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java