Skip to content

Instantly share code, notes, and snippets.

@satwikkansal
Last active October 22, 2022 07:30
Show Gist options
  • Save satwikkansal/aeb88cb3cdafaf49b977cfa320c9c086 to your computer and use it in GitHub Desktop.
Save satwikkansal/aeb88cb3cdafaf49b977cfa320c9c086 to your computer and use it in GitHub Desktop.
Ethereum Smart contract for an Exam Management system written in solidity
pragma solidity ^0.5.12;
contract Exam {
// The assessable element
// The Exam marking system which is responsible for invoking assessment functions.
address owner_ems;
address payable student;
// Main examiners
address primary_examiner_1;
address primary_examiner_2;
address primary_examiner_3;
// Additional examiners
address secondary_examiner_1;
address secondary_examiner_2;
address payable arbiter;
mapping (address => uint) examiner_marks;
mapping (address => bool) marks_submitted;
uint assigned_marks;
uint assigned_marks_timestamp;
constructor (address payable _student,
address _primary1,
address _primary2,
address _primary3,
address _secondary1,
address _secondary2,
address payable _arbiter,
address _ems) public {
student = _student;
primary_examiner_1 = _primary1;
primary_examiner_2 = _primary2;
primary_examiner_3 = _primary3;
secondary_examiner_1 = _secondary1;
secondary_examiner_2 = _secondary2;
arbiter = _arbiter;
}
function get_arbiter_address () public returns (address payable) {
return arbiter;
}
function get_student_address () public returns (address payable) {
return student;
}
function get_primary_examiner(uint examiner_number) public returns (address) {
if (examiner_number == 1) {
return primary_examiner_1;
}
if (examiner_number == 2) {
return primary_examiner_2;
}
if (examiner_number == 3) {
return primary_examiner_3;
}
}
function get_secondary_examiner(uint examiner_number) public returns (address) {
if (examiner_number == 1) {
return secondary_examiner_1;
}
if (examiner_number == 2) {
return secondary_examiner_2;
}
}
function assign_marks(uint marks) public {
require(msg.sender == owner_ems);
assigned_marks = marks;
assigned_marks_timestamp = block.timestamp;
}
function get_assigned_marks () public returns (uint) {
return assigned_marks;
}
function get_result_date () public returns (uint) {
return assigned_marks_timestamp;
}
function add_marks (address examiner, uint marks) public {
require(msg.sender == owner_ems);
examiner_marks[examiner] = marks;
marks_submitted[examiner] = true;
}
function is_primary_evaluation_submitted () public returns (bool) {
return (marks_submitted[primary_examiner_1] &&
marks_submitted[primary_examiner_2] &&
marks_submitted[primary_examiner_3]);
}
function get_primary_examiner_marks (uint examiner_number) public returns (uint) {
if (examiner_number == 1) {
return examiner_marks[primary_examiner_1];
}
if (examiner_number == 2) {
return examiner_marks[primary_examiner_2];
}
if (examiner_number == 3) {
return examiner_marks[primary_examiner_3];
}
}
function is_secondary_evaluation_submitted () public returns (bool) {
return (marks_submitted[secondary_examiner_1] &&
marks_submitted[secondary_examiner_2]);
}
function get_secondary_examiner_marks (uint examiner_number) public returns (uint) {
if (examiner_number == 1) {
return examiner_marks[secondary_examiner_1];
}
if (examiner_number == 2) {
return examiner_marks[secondary_examiner_2];
}
}
}
contract EMS {
address payable university;
enum EvaluationState {NoExamRegistered, PrimaryEvaluationDue, SecondaryEvaluationDue, SecondaryEvaluationDone, RevaluationInProgress, EvaluationFinished}
Exam public exam;
EvaluationState public current_state;
uint primary_difference_threshold = 10;
uint revaluation_difference_threshold = 5;
constructor () public {
current_state = EvaluationState.NoExamRegistered;
university = msg.sender;
}
function register_exam (Exam _exam) public {
require(current_state == EvaluationState.NoExamRegistered);
exam = _exam;
current_state = EvaluationState.PrimaryEvaluationDue;
}
function submit_primary_evaluation (uint marks) public {
require(current_state == EvaluationState.PrimaryEvaluationDue);
require(msg.sender == exam.get_primary_examiner(1) || msg.sender == exam.get_primary_examiner(2) || msg.sender == exam.get_primary_examiner(3));
exam.add_marks(msg.sender, marks);
}
function submit_secondary_evaluation (uint marks) public {
require(current_state == EvaluationState.SecondaryEvaluationDue);
require(msg.sender == exam.get_secondary_examiner(1) || msg.sender == exam.get_secondary_examiner(2));
exam.add_marks(msg.sender, marks);
}
function finalize_primary_evaluation () public {
require(current_state == EvaluationState.PrimaryEvaluationDue);
require(exam.is_primary_evaluation_submitted());
uint marks1 = exam.get_primary_examiner_marks(1);
uint marks2 = exam.get_primary_examiner_marks(2);
uint marks3 = exam.get_primary_examiner_marks(3);
(uint highest, uint lowest) = get_highest_and_lowest_of_three(marks1, marks2, marks3);
uint difference = highest - lowest;
if (difference > primary_difference_threshold) {
// If assigned marks are NOT within 10 points of each other, mark it open for evaluation by secondary examiners.
current_state = EvaluationState.SecondaryEvaluationDue;
} else {
// If assigned marks are within 10 points of each other, then the result is calculated to be the average of the three.
uint average = (marks1 + marks2 + marks3) / 3;
exam.assign_marks(average);
current_state = EvaluationState.EvaluationFinished;
}
}
function finalize_secondary_evaluation () public {
require(current_state == EvaluationState.SecondaryEvaluationDue);
require(exam.is_secondary_evaluation_submitted());
uint pmarks1 = exam.get_primary_examiner_marks(1);
uint pmarks2 = exam.get_primary_examiner_marks(2);
uint pmarks3 = exam.get_primary_examiner_marks(3);
uint smarks1 = exam.get_secondary_examiner_marks(1);
uint smarks2 = exam.get_secondary_examiner_marks(2);
(uint phighest, uint plowest) = get_highest_and_lowest_of_three(pmarks1, pmarks2, pmarks3);
(uint highest, uint temp1) = get_highest_and_lowest_of_three(phighest, smarks2, smarks1);
(uint temp2, uint lowest) = get_highest_and_lowest_of_three(plowest, smarks2, smarks1);
// The highest and lowest mark are discarded and the average of the remaining three is adopted as the actual mark.
uint sum_of_five = pmarks1 + pmarks2 + pmarks3 + smarks1 + smarks2;
uint average_of_three = (sum_of_five - highest - lowest) / 3;
exam.assign_marks(average_of_three);
current_state = EvaluationState.SecondaryEvaluationDone;
}
function accept_marks () public {
require(msg.sender == exam.get_student_address());
require(current_state == EvaluationState.SecondaryEvaluationDone);
// Mark evaluation as finished.
current_state = EvaluationState.EvaluationFinished;
}
function initiate_revaluation () public payable {
// If the decision required additional examiners, the student involved may pay 100 Finney* and request a revision of paper
// within 30 days of publication of the result.
require(current_state == EvaluationState.SecondaryEvaluationDone);
require(msg.value == 100 finney);
require(msg.sender == exam.get_student_address());
require(exam.get_result_date() + 30 days > block.timestamp);
current_state = EvaluationState.RevaluationInProgress;
}
function submit_revaluation (uint new_marks) public {
require(current_state == EvaluationState.RevaluationInProgress);
address payable arbiter = exam.get_arbiter_address();
require(msg.sender == arbiter);
uint current_marks = exam.get_assigned_marks();
uint difference = current_marks - new_marks;
address payable student = exam.get_student_address();
if (difference > revaluation_difference_threshold || difference < -revaluation_difference_threshold) {
// If the updated mark is NOT within 5 marks of the originally assigned one,
// the university gets 20 Finney and the student is refunded the remaining 60 Finney
university.transfer(20 finney);
student.transfer(60 finney);
} else {
// If the updated mark is within 5 marks of the originally assigned one, the university keeps the remaining 80 Finney
university.transfer(80 finney);
}
// The mark is updated as per the final examiner’s opinion.
exam.assign_marks(new_marks);
// In case of a revision of paper, the arbiter gets to assign an updated mark. He or she gets paid 20 Finney (of what the student paid).
arbiter.transfer(20 finney);
// Mark evaluation as finished.
current_state = EvaluationState.EvaluationFinished;
}
function get_highest_and_lowest_of_three (uint marks1, uint marks2, uint marks3) private returns (uint, uint) {
uint highest;
uint lowest;
if (marks1 > marks2) {
// marks1 can be the highest or second highest
if (marks1 > marks3) highest = marks1;
else highest = marks3;
// marks2 can be the lowest or second lowest
if (marks2 < marks3) lowest = marks2;
else lowest = marks3;
} else {
// marks2 can be the highest or second highest
if (marks2 > marks3) highest = marks2;
else highest = marks3;
// marks1 can be the lowest or second lowest
if (marks1 < marks3) lowest = marks1;
else lowest = marks3;
}
return (highest, lowest);
}
}
/*
A = Action
R = Reqiured Constraints
A: Initialize exam marking system contract.
A: Initialize Exam contract.
A: Register the Exam contract with Exam Marking System contract.
A: Submit primary evaluation mark.
R: Role-match i.e. The invoking address should be a primary evaluator.
A: Finalize primary evaluation.
R: All 3 examiners should have submitted their marks.
A: Submit secondary evaluation.
R: Delta b/w primary evaluation should be > 10, and Role-match.
A: finalize_secondary_evaluation
R: All 2 secondary examiners should have submitted their marks.
A: accept_marks
R: Role-match with student
A: initiate_revaluation
R: Role-match with student
A: submit_revaluation
R: Role-match with Arbiter, Student should have initiated revaluation already.
End
{NoExamRegistered, PrimaryEvaluationDue, SecondaryEvaluationDue, SecondaryEvaluationDone, RevaluationInProgress, EvaluationFinished}
*/
pragma solidity ^0.5.12;
contract Exam {
constructor (address payable _student,
address _primary1,
address _primary2,
address _primary3,
address _secondary1,
address _secondary2,
address payable _arbiter) public {
}
function get_arbiter_address () public returns (address payable) {
}
function get_student_address () public returns (address payable) {
}
function get_primary_examiner(uint examiner_number) public returns (address) {
}
function get_secondary_examiner(uint examiner_number) public returns (address) {
}
function assign_marks(uint marks) public {
}
function get_assigned_marks () public returns (uint) {
}
function get_result_date () public returns (uint) {
}
function add_marks (address examiner, uint marks) public {
}
function is_primary_evaluation_submitted () public returns (bool) {
}
function get_primary_examiner_marks (uint examiner_number) public returns (uint) {
}
function is_secondary_evaluation_submitted () public returns (bool) {
}
function get_secondary_examiner_marks (uint examiner_number) public returns (uint) {
}
}
contract EMS {
constructor () public {
}
function register_exam (Exam _exam) public {
}
function submit_primary_evaluation (uint marks) public {
}
function submit_secondary_evaluation (uint marks) public {
}
function finalize_primary_evaluation () public {
// If assigned marks are NOT within 10 points of each other, mark it open for evaluation by secondary examiners
// If assigned marks are within 10 points of each other, then the result is calculated to be the average of the three.
}
function finalize_secondary_evaluation () public {
// The highest and lowest mark are discarded and the average of the remaining three is adopted as the actual mark.
}
function accept_marks () public {
}
function initiate_revaluation () public payable {
// If the decision required additional examiners, the student involved may pay 100 Finney* and request a revision of paper
// within 30 days of publication of the result.
}
function submit_revaluation (uint new_marks) public {
// If the updated mark is NOT within 5 marks of the originally assigned one,
// the university gets 20 Finney and the student is refunded the remaining 60 Finney
// If the updated mark is within 5 marks of the originally assigned one, the university keeps the remaining 80 Finney
// The mark is updated as per the final examiner’s opinion.
// In case of a revision of paper, the arbiter gets to assign an updated mark. He or she gets paid 20 Finney (of what the student paid).
// Mark evaluation as finished.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment