I tested out a few things when voting today since there were like 5 NNS proposals and think the bug is double voting (as you had mentioned).
This is my hypothesis - lets take the following example:
We have neurons A, B, and C:
Neurons B and C follow neuron A
When A, B, and C vote
- if B and C are updated first, then (probably) we have no problem as A then just votes itself.
- if A is updated first, it also starts to update each of its followers’ votes. If this dependency-type update happens before B and C’s requests have hit the backend and updated their votes, then B and C’s requests are rejected, and we get the error on the frontend.
To fix this issue, and to remove the need for double requests, I propose the following solution (that should be fun to implement as well).
Before a user in the NNS app votes, hold the entire dependency tree of just the specific user’s neurons (not external followees) in the app.
In this case, you’d store something like
A
/ \
B C
Then, when the user votes you walk the dependency tree for each “checked” user neuron that is casting a vote down their subtree, adding all neurons in their subtree to a set (unique neurons). Then you only vote with the set of unique “checked” parent nodes, who’s votes will be sent to the NNS which will then propagate those votes to all of the checked children nodes.
Here’s a more complicated example to illustrate the implementation (with more neurons and the followee dependency tree)
A G J K
/ \ /
B C H
/ \ \ /
D E F I
In this example, neurons B, D, F, G, I, and K are checked and vote.
Lets say we iterate through the neurons in the order B, D, F, I, G, K
- B is checked, so we add B to the parent set, and its children D and E to a “visited” child set
- D is checked and has no children, but it is present in the child set (it has already been added by B) so we don’t add it to the parent set (will be covered by B voting)
- F is checked and has no children, so we add it to the parent set
- I is checked and has no children, so we add it to the parent set
- G is checked, so we add G to the set, and its children H and I to the “visited” child set. For each child we visit, we attempt remove it from the parent set if it exists there. I exists in the parent set, so we remove it from the parent set.
- K is checked and has no children, so we add it to the parent set
Then we vote with the neurons that have been added to the parent set: { B, F, G, K }
, and the NNS ends up casting votes for B, D, E, F, G, H, I, and K.
This way, you eliminate any race conditions and need for a second go around trip - plus it eliminates the double voting bug.