Our invariant is that the current quorum verifier has been committed / went through consensus, and I didn't want to break it by assigning it a version that didn't go through consensus. This restriction means that in the NEWLEADER message we'd have to send a config with version 0 and then have follower/observer/learner/leader make a check (when UPTODATE arrives) that detects version = 0 and replaces it with the version from the NEWLEADER version. It seemed that this would require more changes in more places, this is why I chose to do it like in the patch – basically use the fact that lastProposedQV is an uncommitted qv we're sending to everyone, and they already know how to handle it.
Changes to QuorumPeer:
1. Replicating the logic we have for restarting leader election to correctly work when read-only mode is enabled.
+ if (shuttingDownLE)
+ shuttingDownLE = false;
This is just duplicate of what we do for when read-only option is disabled. Without this, restarting leader election doesn't work correctly (it keeps spinning since shuttingDownLE = true. I noticed it because read-only test was failing with my changes to Leader.java. After this changed work, I changed FastLeaderElection not to restart in this case because the quorum verifier is identical besides the version. The change above is still needed though.
The other two changes are there because I was hitting NullPointerException from different tests that now had to invoke processReconfig (to write dynamic config files with new version) but didn't initialize dynamic config related parameters correctly. These changes are just performing sanity checks before using variables that may be null.