Implement multi-node transaction voting
Currently, transactions can only handle the trivial case of one single node voting. This was mostly done to keep initial complexity low, but in the end it is rather useless to vote when there's only one voter. This restriction is now lifted.
The implementation is quite simple: instead of storing the expected voter's name, only, we store a map of votes which is initialized to the set of expected voters. Upon receiving a vote, we will check that the voter is expected and has not set up a vote yet. If the check succeeds, we register his vote.
Concurrency is handled via two channels, doneCh
and cancelCh
. The
latter may be executed via the cancel callback and aborts all
transactions currently in the collectVotes()
phase. doneCh
will be
closed as soon as the last voter has cast its vote and thus allow
collectVotes()
to finish. Note that it's each voter's own
responsibility to count votes, which is mostly done in order to keep
complexity of the code low. As
- only the last voter may close a channel
- we know each voter up front
- no voter may cast votes more than once
we know that only a single node may ever close the doneCh
.
This commit also adds a set of tests to verify code is working as expected. One of the pre-existing tests that verified that we can only ever register a single node, only, which was done as a precaution so that we actually verify this and not run into any unsupported voting setups. As we now support multiple nodes, this test is removed.
Note that I've also included some unrelated cleanups which I found worthwhile to have. I'm happy to move these into a separate MR if you think it worthwhile, the changes are independent anyway. Please just let me know.
References #2635 (closed)