diff --git a/lesson3_violations/Borda/BordaMissingRule.spec b/lesson3_violations/Borda/BordaMissingRule.spec new file mode 100644 index 0000000..b4cc874 --- /dev/null +++ b/lesson3_violations/Borda/BordaMissingRule.spec @@ -0,0 +1,28 @@ +/* + * Borda Missing Rule by Perito Flores + * ------------- + * + * Verification of a simple voting contract which uses a Borda election. + * See https://en.wikipedia.org/wiki/Borda_count + */ + + + +methods { + function points(address) external returns uint256 envfree; + function vote(address,address,address) external; + function voted(address) external returns bool envfree; + function winner() external returns address envfree; +} + + + +rule BordaMissingRule(env e,method m){ + + require m.selector != sig:vote(address,address,address).selector; + address winnerBefore = winner(); + calldataarg args; + m(e,args); + address winnerAfter = winner(); + assert winnerAfter == winnerBefore , "The winner can be changed only after voting"; +} diff --git a/lesson3_violations/Borda/BordaNewBug.sol b/lesson3_violations/Borda/BordaNewBug.sol new file mode 100644 index 0000000..6fee828 --- /dev/null +++ b/lesson3_violations/Borda/BordaNewBug.sol @@ -0,0 +1,52 @@ +pragma solidity ^0.8.0; +import "./IBorda.sol"; + +contract BordaNewBug is IBorda{ + + // The current winner + address public _winner; + + // A map storing whether an address has already voted. Initialized to false. + mapping (address => bool) _voted; + + // Points each candidate has recieved, initialized to zero. + mapping (address => uint256) _points; + + // current maximum points of all candidates. + uint256 public pointsOfWinner; + + + function vote(address f, address s, address t) public override { + require(!_voted[msg.sender], "this voter has already cast its vote"); + require( f != s && f != t && s != t, "candidates are not different"); + _voted[msg.sender] = true; + voteTo(f, 3); + voteTo(s, 2); + voteTo(t, 1); + } + + function voteTo(address c, uint256 p) private { + //update points:w + _points[c] = _points[c]+ p; + // update winner if needed + if (_points[c] > _points[_winner] ) { + _winner = c; + } + } + function switchWinner(address newWinner) external { + require (points(newWinner)>=points(_winner)); + _winner = newWinner; + } + + function winner() external view override returns (address) { + return _winner; + } + + function points(address c) public view override returns (uint256) { + return _points[c]; + } + + function voted(address x) public view override returns(bool) { + return _voted[x]; + } +} diff --git a/lesson3_violations/Borda/BordaNewBugRuns.sh b/lesson3_violations/Borda/BordaNewBugRuns.sh new file mode 100644 index 0000000..02b7f12 --- /dev/null +++ b/lesson3_violations/Borda/BordaNewBugRuns.sh @@ -0,0 +1,7 @@ +echo Runing the specs... + +certoraRun Borda.sol --verify Borda:BordaMissingRule.spec --msg 'Missing rule also pass in the original' + +certoraRun BordaNewBug.sol --verify BordaNewBug:Borda.spec --msg 'Original rules passes in the buggy file' + +certoraRun BordaNewBug.sol --verify BordaNewBug:BordaMissingRule.spec --msg 'New rule catches the bug'