@Override
  public PayloadIdentifier preparePayload(
      final BlockHeader parentHeader,
      final Long timestamp,
      final Bytes32 prevRandao,
      final Address feeRecipient,
      final Optional<List<Withdrawal>> withdrawals,
      final Optional<Bytes32> parentBeaconBlockRoot) {

    // we assume that preparePayload is always called sequentially, since the RPC Engine calls
    // are sequential, if this assumption changes then more synchronization should be added to
    // shared data structures

    final PayloadIdentifier payloadIdentifier =
        PayloadIdentifier.forPayloadParams(
            parentHeader.getBlockHash(),
            timestamp,
            prevRandao,
            feeRecipient,
            withdrawals,
            parentBeaconBlockRoot);

    if (blockCreationTasks.containsKey(payloadIdentifier)) {
      LOG.debug(
          "Block proposal for the same payload id {} already present, nothing to do",
          payloadIdentifier);
      return payloadIdentifier;
    }
    // it's a new payloadId so...
    cancelAnyExistingBlockCreationTasks(payloadIdentifier);

    final MergeBlockCreator mergeBlockCreator =
        this.mergeBlockCreatorFactory.forParams(parentHeader, Optional.ofNullable(feeRecipient));

    blockCreationTasks.put(payloadIdentifier, new BlockCreationTask(mergeBlockCreator));

    // put the empty block in first
    final Block emptyBlock =
        mergeBlockCreator
            .createBlock(
                Optional.of(Collections.emptyList()),
                prevRandao,
                timestamp,
                withdrawals,
                parentBeaconBlockRoot,
                parentHeader)
            .getBlock();

    BlockProcessingResult result = validateProposedBlock(emptyBlock);
    if (result.isSuccessful()) {
      mergeContext.putPayloadById(
          new PayloadWrapper(
              payloadIdentifier,
              new BlockWithReceipts(emptyBlock, result.getReceipts()),
              result.getRequests()));
      LOG.info(
          "Start building proposals for block {} identified by {}",
          emptyBlock.getHeader().getNumber(),
          payloadIdentifier);
    } else {
      LOG.warn(
          "failed to validate empty block proposal {}, reason {}",
          emptyBlock.getHash(),
          result.errorMessage);
      if (result.causedBy().isPresent()) {
        LOG.warn("caused by", result.causedBy().get());
      }
    }

    tryToBuildBetterBlock(
        timestamp,
        prevRandao,
        payloadIdentifier,
        mergeBlockCreator,
        withdrawals,
        parentBeaconBlockRoot,
        parentHeader);

    return payloadIdentifier;
  }
Instantiates a new Merge coordinator.

@param protocolContext the protocol context
@param protocolSchedule the protocol schedule
@param ethScheduler the block builder executor
@param miningParams the mining params
@param backwardSyncContext the backward sync context
@param mergeBlockCreatorFactory the merge block creator factory
consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java