private Optional<Transaction> buildTransaction(
      final CallParameter callParams,
      final TransactionValidationParams transactionValidationParams,
      final ProcessableBlockHeader processableHeader,
      final Address senderAddress,
      final long nonce,
      final long gasLimit,
      final Wei blobGasPrice,
      final Supplier<SECPSignature> signatureSupplier) {

    final Wei value = callParams.getValue().orElse(Wei.ZERO);
    final Bytes payload = callParams.getPayload().orElse(Bytes.EMPTY);

    final Transaction.Builder transactionBuilder =
        Transaction.builder()
            .nonce(nonce)
            .gasLimit(gasLimit)
            .sender(senderAddress)
            .value(value)
            .payload(payload)
            .signature(signatureSupplier.get());

    callParams.getTo().ifPresent(transactionBuilder::to);

    // Set access list if present
    callParams.getAccessList().ifPresent(transactionBuilder::accessList);
    // Set versioned hashes if present
    callParams.getBlobVersionedHashes().ifPresent(transactionBuilder::versionedHashes);

    final Wei gasPrice;
    final Wei maxFeePerGas;
    final Wei maxPriorityFeePerGas;
    final Wei maxFeePerBlobGas;
    if (transactionValidationParams.isAllowExceedingBalance()) {
      gasPrice = Wei.ZERO;
      maxFeePerGas = Wei.ZERO;
      maxPriorityFeePerGas = Wei.ZERO;
      maxFeePerBlobGas = Wei.ZERO;
    } else {
      gasPrice = callParams.getGasPrice().orElse(Wei.ZERO);
      maxFeePerGas = callParams.getMaxFeePerGas().orElse(gasPrice);
      maxPriorityFeePerGas = callParams.getMaxPriorityFeePerGas().orElse(gasPrice);
      maxFeePerBlobGas = callParams.getMaxFeePerBlobGas().orElse(blobGasPrice);
    }

    if (shouldSetGasPrice(callParams, processableHeader)) {
      transactionBuilder.gasPrice(gasPrice);
    }

    if (shouldSetMaxFeePerGas(callParams, processableHeader)) {
      transactionBuilder.maxFeePerGas(maxFeePerGas).maxPriorityFeePerGas(maxPriorityFeePerGas);
    }

    if (shouldSetBlobGasPrice(callParams)) {
      transactionBuilder.maxFeePerBlobGas(maxFeePerBlobGas);
    }

    transactionBuilder.guessType();

    if (transactionBuilder.getTransactionType().requiresChainId()) {
      callParams
          .getChainId()
          .ifPresentOrElse(
              transactionBuilder::chainId,
              () ->
                  // needed to make some transactions valid
                  transactionBuilder.chainId(protocolSchedule.getChainId().orElse(BigInteger.ONE)));
    }

    final Transaction transaction = transactionBuilder.build();
    return Optional.ofNullable(transaction);
  }
Processes a transaction simulation with the provided parameters and executes pre-worldstate
close actions.

@param callParams The call parameters for the transaction.
@param maybeStateOverrides The map of state overrides to apply to the state for this
    transaction.
@param transactionValidationParams The validation parameters for the transaction.
@param operationTracer The tracer for capturing operations during processing.
@param preWorldStateCloseGuard The pre-worldstate close guard for executing pre-close actions.
@param header The block header.
@return An Optional containing the result of the processing.
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java