public void transitionToVoted(
        int epoch,
        ReplicaKey candidateKey
    ) {
        int currentEpoch = state.epoch();
        if (localId.isPresent() && candidateKey.id() == localId.getAsInt()) {
            throw new IllegalStateException(
                String.format(
                    "Cannot transition to Voted for %s and epoch %d since it matches the local " +
                    "broker.id",
                    candidateKey,
                    epoch
                )
            );
        } else if (!localId.isPresent()) {
            throw new IllegalStateException("Cannot transition to voted without a replica id");
        } else if (epoch < currentEpoch) {
            throw new IllegalStateException(
                String.format(
                    "Cannot transition to Voted for %s and epoch %d since the current epoch " +
                    "(%d) is larger",
                    candidateKey,
                    epoch,
                    currentEpoch
                )
            );
        } else if (epoch == currentEpoch && !isUnattached()) {
            throw new IllegalStateException(
                String.format(
                    "Cannot transition to Voted for %s and epoch %d from the current state (%s)",
                    candidateKey,
                    epoch,
                    state
                )
            );
        }

        // Note that we reset the election timeout after voting for a candidate because we
        // know that the candidate has at least as good of a chance of getting elected as us
        durableTransitionTo(
            new VotedState(
                time,
                epoch,
                candidateKey,
                partitionState.lastVoterSet().voterIds(),
                state.highWatermark(),
                randomElectionTimeoutMs(),
                logContext
            )
        );
    }
Grant a vote to a candidate and become a follower for this epoch. We will remain in this
state until either the election timeout expires or a leader is elected. In particular,
we do not begin fetching until the election has concluded and
{@link #transitionToFollower(int, int, Endpoints)} is invoked.
raft/src/main/java/org/apache/kafka/raft/QuorumState.java