예제 #1
0
async def _random_vote(vote_factory: DefaultVoteFactory):
    r = random.randint(0, 15)
    if r < 5:
        return DefaultVote(id_=os.urandom(16),
                           data_id=os.urandom(16),
                           commit_id=os.urandom(16),
                           voter_id=vote_factory._node_id,
                           epoch_num=random.randint(0, 10),
                           round_num=random.randint(0, 10))
    elif r < 10:
        return vote_factory.create_lazy_vote(voter_id=vote_factory._node_id,
                                             epoch_num=random.randint(0, 10),
                                             round_num=random.randint(0, 10))
    else:
        return vote_factory.create_none_vote(epoch_num=random.randint(0, 10),
                                             round_num=random.randint(0, 10))
예제 #2
0
async def test_round_data_vote_sync():
    round_num = 0
    voter_num = 7

    async with setup_items(voter_num,
                           round_num) as (voters, event_system, round_,
                                          election, epoch, candidate_data,
                                          candidate_votes):

        data = await round_._data_factory.create_data(
            data_number=candidate_data.number + 1,
            prev_id=candidate_data.id,
            epoch_num=epoch.num,
            round_num=round_num,
            prev_votes=candidate_votes)
        vote_factories = [DefaultVoteFactory(voter) for voter in voters]
        votes = []
        for vote_factory in vote_factories:
            vote = await vote_factory.create_vote(data.id, candidate_data.id,
                                                  epoch.num, round_num)
            votes.append(vote)
            await round_.receive_vote(vote)

        election.receive_vote.assert_not_called()

        await round_.receive_data(data)

        assert len(votes) == len(election.receive_vote.call_args_list)
        for vote, call_args in zip(votes,
                                   election.receive_vote.call_args_list):
            arg_vote, = call_args[0]
            assert arg_vote is vote
예제 #3
0
async def setup(voter_num: int):
    voters = [os.urandom(16) for _ in range(voter_num)]
    vote_factories = [DefaultVoteFactory(voter) for voter in voters]
    random.shuffle(vote_factories)

    quorum = random.randint(2, len(vote_factories))
    return voters, vote_factories, quorum, RoundMessages()
예제 #4
0
async def test_round_reach_quorum_consensus(voter_num: int):
    round_num = 0

    async with setup_items(voter_num,
                           round_num) as (voters, event_system, round_,
                                          election, epoch, candidate_data,
                                          candidate_votes):
        # Propose LazyData
        await round_.round_start()

        mediator = event_system.get_mediator(DelayedEventMediator)
        mediator.execute.assert_called_once()

        delay, event = mediator.execute.call_args_list[0][0]
        assert delay == TIMEOUT_PROPOSE
        assert isinstance(event, ReceiveDataEvent)
        assert event.data.is_lazy()

        mediator.execute.reset_mock()

        vote_factories = [DefaultVoteFactory(voter) for voter in voters]
        random.shuffle(vote_factories)

        quorum_vote_factories = vote_factories[:epoch.quorum_num]
        for vote_factory in quorum_vote_factories:
            vote = await vote_factory.create_vote(b'test', candidate_data.id,
                                                  epoch.num, round_num)
            await round_.receive_vote(vote)

        mediator.execute.assert_not_called()
예제 #5
0
async def do_votes(election, success_vote_num, none_vote_num, lazy_vote_num, voters):
    validator_vote_factories = [DefaultVoteFactory(x) for x in voters]

    for i in range(success_vote_num):
        await do_vote(
            election,
            await validator_vote_factories[i].create_vote(
                data_id=PROPOSE_ID,
                commit_id=CANDIDATE_ID,
                epoch_num=0,
                round_num=1
            )
        )
    for i in range(none_vote_num):
        await do_vote(
            election,
            validator_vote_factories[success_vote_num + i].create_none_vote(
                epoch_num=0,
                round_num=1
            )
        )
    for i in range(lazy_vote_num):
        await do_vote(
            election,
            validator_vote_factories[i].create_lazy_vote(
                voter_id=voters[i],
                epoch_num=0,
                round_num=1
            )
        )
예제 #6
0
async def setup_items(voter_num: int, round_num: int):
    voters = [os.urandom(16) for _ in range(voter_num)]
    voter = voters[0]

    epoch = RotateEpoch(1, voters)
    event_system = MagicMock(EventSystem(use_priority=True))

    data_factory = DefaultDataFactory(voter)
    vote_factory = DefaultVoteFactory(voter)

    election = MagicMock(
        Election(voter, epoch, round_num, event_system, data_factory,
                 vote_factory, DataPool(), VotePool()))
    round_ = Round(election, voter, epoch, round_num, event_system,
                   data_factory, vote_factory)

    try:
        genesis_epoch_num = 0
        genesis_round_num = 0
        genesis_data = await data_factory.create_data(0, b'',
                                                      genesis_epoch_num,
                                                      genesis_round_num, ())
        genesis_votes = ()

        candidate_data = genesis_data
        candidate_votes = genesis_votes
        yield voters, event_system, round_, election, epoch, candidate_data, candidate_votes
    finally:
        pass
예제 #7
0
async def setup_consensus():
    node_id = b'x'
    event_system = MagicMock(EventSystem())
    data_factory = MagicMock(DefaultDataFactory(node_id))
    vote_factory = MagicMock(DefaultVoteFactory(node_id))
    consensus = Consensus(event_system,
                          node_id=node_id,
                          data_factory=data_factory,
                          vote_factory=vote_factory)
    return event_system, consensus
예제 #8
0
async def setup_consensus():
    def _new_round_mock(self, epoch_num: int, round_num: int, candidate_id: bytes):
        epoch = self._get_epoch(epoch_num)
        new_round = RoundMock(epoch, round_num)
        new_round.candidate_id = candidate_id
        self._round_pool.add_round(new_round)
        return new_round

    voters = [bytes([x]) for x in range(4)]
    vote_factories = [DefaultVoteFactory(voter) for voter in voters]

    event_system = MagicMock(EventSystem())
    data_factory = MagicMock(DefaultDataFactory(voters[0]))
    vote_factory = MagicMock(DefaultVoteFactory(voters[0]))
    consensus = Consensus(event_system,
                          voters[0],
                          data_factory,
                          vote_factory)
    consensus._new_round = partial(_new_round_mock, consensus)

    genesis_epoch = RotateEpoch(0, [])
    now_epoch = RotateEpoch(1, voters)
    epochs = [genesis_epoch, now_epoch]

    genesis_data = DefaultData(
        id_=b"genesis",
        prev_id=None,
        proposer_id=None,
        number=0,
        epoch_num=0,
        round_num=0,
        prev_votes=[]
    )

    datums = [genesis_data]
    votes = []

    await consensus.initialize(commit_id=genesis_data.prev_id, epoch_pool=epochs, data_pool=datums, vote_pool=votes)
    return consensus, voters, vote_factories, now_epoch, genesis_data
예제 #9
0
async def setup(voter_num: int):
    voters = [os.urandom(16) for _ in range(voter_num)]
    vote_factories = [DefaultVoteFactory(voter) for voter in voters]
    random.shuffle(vote_factories)

    data_factory = DefaultDataFactory(voters[0])
    data = await data_factory.create_data(data_number=0,
                                          prev_id=os.urandom(16),
                                          epoch_num=0,
                                          round_num=0,
                                          prev_votes=())
    quorum = random.randint(1, len(vote_factories))
    return voters, vote_factories, quorum, data, RoundMessages()
예제 #10
0
async def test_round_reach_quorum(voter_num: int):
    round_num = 0

    async with setup_items(voter_num,
                           round_num) as (voters, event_system, round_,
                                          election, epoch, candidate_data,
                                          candidate_votes):
        # Propose LazyData
        await round_.round_start()

        mediator = event_system.get_mediator(DelayedEventMediator)
        mediator.execute.assert_called_once()

        delay, event = mediator.execute.call_args_list[0][0]
        assert delay == TIMEOUT_PROPOSE
        assert isinstance(event, ReceiveDataEvent)
        assert event.data.is_lazy()

        mediator.execute.reset_mock()

        random.shuffle(voters)
        vote_factories = [DefaultVoteFactory(voter) for voter in voters]

        quorum_vote_factories = vote_factories[:epoch.quorum_num]
        for vote_factory in quorum_vote_factories[:-1]:
            vote = await vote_factory.create_vote(b"test", candidate_data.id,
                                                  epoch.num, round_num)
            await round_.receive_vote(vote)

        mediator.execute.assert_not_called()

        none_vote = quorum_vote_factories[-1].create_none_vote(
            epoch.num, round_num)
        await round_.receive_vote(none_vote)

        assert len(mediator.execute.call_args_list) == len(voters)

        for voter, call_args in zip(voters, mediator.execute.call_args_list):
            timeout, event = call_args[0]
            assert timeout == TIMEOUT_VOTE
            assert isinstance(event, ReceiveVoteEvent)
            assert event.vote.is_lazy()
        mediator.execute.reset_mock()

        none_vote = vote_factories[-1].create_none_vote(epoch.num, round_num)
        await round_.receive_vote(none_vote)

        mediator.execute.assert_not_called()
예제 #11
0
async def test_round_failure_lazy():
    epoch, round_num, election_messages, data, voters = await setup()

    # Round must add LazyData on RoundStart
    lazy_data = DefaultDataFactory(voters[0]).create_lazy_data(
        epoch.num, round_num, epoch.get_proposer_id(round_num))
    election_messages.add_data(lazy_data)

    for voter in voters[:epoch.quorum_num]:
        vote = DefaultVoteFactory(voter).create_lazy_vote(
            voter, epoch.num, round_num)
        election_messages.add_vote(vote)
    election_messages.update()
    candidate = election_messages.result

    assert candidate is None
예제 #12
0
async def setup_election(
        peer_num: int) -> Tuple[EventSystem, Election, List[bytes]]:
    event_system = MagicMock(EventSystem())
    voters = [bytes([x]) for x in range(peer_num)]
    data_factory = DefaultDataFactory(TEST_NODE_ID)
    vote_factory = DefaultVoteFactory(TEST_NODE_ID)
    data_pool = DataPool()
    vote_pool = VotePool()

    genesis_data = DefaultData(id_=CANDIDATE_ID,
                               prev_id=b'',
                               proposer_id=TEST_NODE_ID,
                               number=0,
                               epoch_num=0,
                               round_num=0,
                               prev_votes=())
    data_pool.add_data(genesis_data)

    election = Election(TEST_NODE_ID, RotateEpoch(0, voters),
                        genesis_data.round_num + 1, event_system, data_factory,
                        vote_factory, data_pool, vote_pool)
    election._candidate_id = CANDIDATE_ID
    return event_system, election, voters
예제 #13
0
async def test_round_none_vote_received():
    round_num = 0
    voter_num = 7

    async with setup_items(voter_num,
                           round_num) as (voters, event_system, round_,
                                          election, epoch, candidate_data,
                                          candidate_votes):
        #  Propose NoneData
        await round_.round_start()

        random.shuffle(voters)
        none_votes = []
        for voter in voters[:epoch.quorum_num]:
            none_vote = DefaultVoteFactory(voter).create_none_vote(
                epoch.num, round_num)
            none_votes.append(none_vote)
            await round_.receive_vote(none_vote)

        assert len(election.receive_vote.call_args_list) == epoch.quorum_num
        for none_vote, call_args in zip(none_votes,
                                        election.receive_vote.call_args_list):
            vote, = call_args[0]
            assert vote is none_vote
예제 #14
0
    RoundEndEvent(True,
                  epoch_num=1,
                  round_num=1,
                  candidate_id=b'd2',
                  commit_id=b'd1'),
]
params["normal"]["commit_id"] = b''

params["lazy"] = {}
params["lazy"]["epochs"] = [
    RotateEpoch(num=0, voters=[]),
    RotateEpoch(num=1, voters=[b'a'])
]
params["lazy"]["votes"] = [
    DefaultVoteFactory(b'').create_lazy_vote(voter_id=b'a',
                                             epoch_num=1,
                                             round_num=0),
    DefaultVoteFactory(b'').create_lazy_vote(voter_id=b'a',
                                             epoch_num=1,
                                             round_num=1),
    DefaultVote(b'v0',
                data_id=b'd1',
                commit_id=b'd0',
                voter_id=b'a',
                epoch_num=1,
                round_num=3),
]
params["lazy"]["datums"] = [
    DefaultData(b'd0',
                prev_id=b'',
                proposer_id=b'',