Fuzz test
Fuzz Testing Summary¶
The fuzz testing of the D21 voting system was completed successfully. The script tested various functions, including voter registration, voting, and result sorting. No errors or issues were found, indicating the system's resilience to diverse input scenarios and its adherence to the defined voting rules. This result supports the system's reliability and correctness in its current state.
from wake.testing import *
from pytypes.contracts.D21 import D21
from wake.testing.fuzzing import *
import random
from typing import Dict, List, Tuple
class D21FuzzTest(FuzzTest):
d21_contract: D21
owner: Address
subjects: List[Address]
tracked_votes: Dict[Address, int]
voters: List[Address]
votes_cast: Dict[Address, Tuple[int, int]] # Tuple format: (positive_votes, negative_votes)
voted_for_subject: Dict[Address, Dict[Address, bool]]
voting_started: bool # Indicates whether the voting period has started
voting_ended: bool # Indicates whether the voting period has ended
# Contract initialization and state setup
def pre_sequence(self) -> None:
self.owner = default_chain.accounts[0]
self.d21_contract = D21.deploy(from_=self.owner)
self.subjects = []
self.voters = []
self.votes_cast = {}
self.voting_started = False
self.voting_ended = False
self.tracked_votes = {}
self.voted_for_subject = {}
@flow(precondition=lambda self: not self.voting_started)
def flow_addSubject(self):
print("flow_addSubject")
subject_name = random_string(5, 20)
subject_address = random_address()
self.d21_contract.addSubject(subject_name, from_=subject_address)
self.subjects.append(subject_address)
self.tracked_votes[subject_address] = 0
@flow(precondition=lambda self: not self.voting_started)
def flow_addVoter(self):
print("flow_addVoter")
voter = random_account()
self.d21_contract.addVoter(voter, from_=self.owner)
self.voters.append(voter.address)
self.votes_cast[voter.address] = (0, 0)
@flow(
precondition=lambda self:
not self.voting_started and
len(self.subjects) > 5 and
len(self.voters) > 20
)
def flow_startVoting(self):
print("flow_startVoting")
self.d21_contract.startVoting(from_=self.owner)
self.voting_started = True
@flow(
precondition=lambda self:
self.voting_started and
not self.voting_ended and
len(self.subjects) > 0 and
len(self.voters) > 0
)
def flow_votePositive(self):
print("flow_votePositive")
voter = random.choice(self.voters)
subject = random.choice(self.subjects)
positive_votes, negative_votes = self.votes_cast.get(voter, (0, 0))
vote_status = self.voted_for_subject.get(voter, {}).get(subject, False)
if positive_votes < 3 and not vote_status:
self.d21_contract.votePositive(subject, from_=voter)
self.votes_cast[voter] = (positive_votes + 1, negative_votes)
self.tracked_votes[subject] += 1
if voter not in self.voted_for_subject:
self.voted_for_subject[voter] = {}
self.voted_for_subject[voter][subject] = True
@flow(
precondition=lambda self:
self.voting_started and
not self.voting_ended and
len(self.subjects) > 0 and
len(self.voters) > 0
)
def flow_voteNegative(self):
print("flow_voteNegative")
voter = random.choice(self.voters) # Randomly select a voter
subject = random.choice(self.subjects) # Randomly select a subject
positive_votes, negative_votes = self.votes_cast.get(voter, (0, 0))
vote_status = self.voted_for_subject.get(voter, {}).get(subject, False)
# Check if the voter has cast at least two positive votes and no negative votes
if positive_votes >= 2 and negative_votes < 1 and not vote_status:
self.d21_contract.voteNegative(subject, from_=voter)
self.votes_cast[voter] = (positive_votes, negative_votes + 1)
self.tracked_votes[subject] -= 1
if voter not in self.voted_for_subject:
self.voted_for_subject[voter] = {}
self.voted_for_subject[voter][subject] = True
@invariant()
def invariant_checkState(self) -> None:
print("invariant_checkState")
contract_owner = read_storage_variable(self.d21_contract,'owner')
contract_subjects = self.d21_contract.getSubjects()
# Check if the contract owner matches the expected owner
assert contract_owner == self.owner.address
# Check if the list of subjects in the contract matches the expected list
assert set(contract_subjects) == set(self.subjects)
# Validate the vote counts for each subject
for subject_addr in self.subjects:
contract_subject = self.d21_contract.getSubject(subject_addr)
expected_votes = self.tracked_votes[subject_addr]
assert contract_subject.votes == expected_votes
# Retrieve the voting results from the contract
contract_results = self.d21_contract.getResults()
# Check if the results are sorted in descending order by vote count
sorted_results = sorted(contract_results, key=lambda subject: subject.votes, reverse=True)
assert contract_results == sorted_results
@default_chain.connect()
def test_fuzz():
D21FuzzTest().run(sequences_count=30, flows_count=100)