@pytest.mark.parametrize('n_voters', range(8))
def test_vote_actions(n_voters):
    '* Legal transitions are UNDECIDED -> [VALID|INVALID] only\n    * Block is never left UNDECIDED after voting\n    * Accomodates rogues on previous block / invalid schema\n    '

    class TestVoting(Voting):

        @classmethod
        def verify_vote_schema(cls, vote):
            return (type(vote['vote']['is_block_valid']) == bool)

        @classmethod
        def verify_vote_signature(cls, vote):
            return True
    keyring = 'abcdefghijklmnopqrstuvwxyz'[:n_voters]
    block = {'id': 'block', 'block': {'voters': keyring}}
    state = UNDECIDED
    todo = [(state, [], [])]

    def branch(p, r):
        todo.append((state, votes, (votes + [{'node_pubkey': keyring[len(votes)], 'vote': {'previous_block': p, 'is_block_valid': r}}])))
    while todo:
        (prev_state, prev_votes, votes) = todo.pop(0)
        results = Counter((v['vote']['is_block_valid'] for v in votes))
        prev_blocks = Counter((v['vote']['previous_block'] for v in votes))
        majority = ((n_voters // 2) + 1)
        honest = ((len(votes) == majority) and (len(prev_blocks) == 1) and (not results['lol']) and (len(results) == 1))
        closed = (len(votes) == n_voters)
        if votes:
            state = TestVoting.block_election(block, votes, keyring)['status']
            assert (prev_state in [state, UNDECIDED])
        if (honest or closed):
            assert ((state != UNDECIDED) or (n_voters == 0))
        if closed:
            continue
        branch('A', True)
        branch('B', True)
        branch('A', False)
        branch('A', 'lol')
* Legal transitions are UNDECIDED -> [VALID|INVALID] only
* Block is never left UNDECIDED after voting
* Accomodates rogues on previous block / invalid schema
@pytest.mark.parametrize('n_voters', range(8))
def test_vote_actions(n_voters):
    '* Legal transitions are UNDECIDED -> [VALID|INVALID] only\n    * Block is never left UNDECIDED after voting\n    * Accomodates rogues on previous block / invalid schema\n    '

    class TestVoting(Voting):

        @classmethod
        def verify_vote_schema(cls, vote):
            return (type(vote['vote']['is_block_valid']) == bool)

        @classmethod
        def verify_vote_signature(cls, vote):
            return True
    keyring = 'abcdefghijklmnopqrstuvwxyz'[:n_voters]
    block = {'id': 'block', 'block': {'voters': keyring}}
    state = UNDECIDED
    todo = [(state, [], [])]

    def branch(p, r):
        todo.append((state, votes, (votes + [{'node_pubkey': keyring[len(votes)], 'vote': {'previous_block': p, 'is_block_valid': r}}])))
    while todo:
        (prev_state, prev_votes, votes) = todo.pop(0)
        results = Counter((v['vote']['is_block_valid'] for v in votes))
        prev_blocks = Counter((v['vote']['previous_block'] for v in votes))
        majority = ((n_voters // 2) + 1)
        honest = ((len(votes) == majority) and (len(prev_blocks) == 1) and (not results['lol']) and (len(results) == 1))
        closed = (len(votes) == n_voters)
        if votes:
            state = TestVoting.block_election(block, votes, keyring)['status']
            assert (prev_state in [state, UNDECIDED])
        if (honest or closed):
            assert ((state != UNDECIDED) or (n_voters == 0))
        if closed:
            continue
        branch('A', True)
        branch('B', True)
        branch('A', False)
        branch('A', 'lol')