Skip to content

Voter registration exercise

celestebarnaby edited this page Jul 3, 2017 · 46 revisions

Voter Registration

You are tasked with designing a voter registration system for a small democratic nation. Every citizen of this country has a valid ID card with a corresponding number. The country maintains a ledger of the ID numbers of all citizens. The process of registering to vote is as follows:

  • A citizen who is not registered to vote can fill out and submit a registration application with certain pertinent information (e.g. name, address, age, ID number, etc.)
  • On the application, the citizen can choose to register with one of the parties, party #1 or party #2, or to not register with a party.
  • The application is then processed, in order to ascertain that the citizen meets all the requirements necessary in order to vote (e.g. they are old enough, they have a valid name and ID number, etc.). While the application is being processed, the citizen cannot vote, and they cannot submit another application.
  • Once an application has been processed, the citizen either accepted or rejected. If they are accepted, they are able to vote in national elections. If they chose to register with a political party, they are also able to vote in elections specific to that party. A citizen who has been accepted is not able to submit a new registration application.
  • If a citizen was rejected, they are not able to vote in any elections, and they cannot submit a new registration application.

Part 1a

Describe using words and drawings how you would design a program that allows citizens to submit an application and takes appropriate action based on the current status of that citizen.

Part 1b

Design, using pseudocode, a system to handle voter registration. You can make the following assumptions:

  • There is a ledger of the names and ID numbers of all citizens, which you (the developer of the program) have access to.
  • On the registration form, a citizen fills in their name, age, ID number, and which party they want to register with: party #1 or party #2.
  • The only criteria for being eligible to vote are that the citizen is over 18 and has a valid name and ID number.

Do not attempt to write code that resembles any particular language. We want to see the kind of code you would want to be able to write. The goal here is to see how people naturally go about solving problems like this.

Part 2

One possible approach to solving this problem is using states. Here is an example of what a state diagram for this program may look:

Redesign your system to include the specific states and state transitions shown in this diagram. State-specific actions should only be possible in the appropriate state. For instance, you should only be able to access/use the information in the ledger of citizens while you are in the processing state.

Part 3

Here is, broadly, what an implementation of this system may look like in Obsidian. This implementation defines states and transactions, but transitions between states in the Citizen contract are still missing. Your task here is to add state transitions to this code. You may write them however makes the most sense for the design of the program. The result of calling submitApplication should be that the citizen is in either the CanVote or CannotVote state. Places where you may want to add state transitions are marked with //TODO.

contract Application {
    string name;
    int age;
    int idNum;
    int whichParty;

    Application(string name, int age, int idNum, int whichParty) {
        this.name = name;
        this.age = age;
        this.idNum = idNum;
        this.whichParty = whichParty;
    }

    transaction getAge() returns int {
        return this.age;
    }

    transaction getIdNum() returns int {
        return idNum;
    }

    transaction getWhichParty() returns int {
        return this.whichParty;
    }
}

contract Citizen {

    Citizen() {
      //TODO
      
    }

    state Unregistered {

        transaction submitApplication(string name, int age, int idNum, int whichParty) {
            Application app = new Application(name, age, idNum, whichParty);
            //TODO
        }
    }

    state Processing {
        Application app;

        transaction processApplication() {
            bool canVote = false;
            // In this transaction we access the ledger and check whether the name, age,
            // and ID number listed on app are valid. If they are, canVote is set to true.

            if (canVote) {
                //TODO
     
            } else {
               //TODO
            }
        }
    }

    state CanVote {
        Application app;

        transaction checkParty() {
        //assume that if they listed a number besides 1 or 2 it means they chose not to register with a party
           if (app.getWhichParty() == 1) {
               //TODO
 
           }

           if (app.getWhichParty() == 2) {
               //TODO
           }
        }

        transaction submitApplication(string name, int age, int idNum, int whichParty) {
            //TODO: this transaction handles what happens if a citizen who is
            //registered to vote attempts to submit a new application.
            }

        state Party1 {

        }

        state Party2 {

        }
    }

    state CannotVote {

        transaction submitApplication(string name, int age, int idNum, int whichParty) {
            //TODO: this transaction handles what happens if a citizen who is
            //ineligible to vote attempts to submit a new application.
        }
    }
}

Part 4

Provided below are several different options for writing state transitions in Obsidian. Which of them makes the most sense to you/which do you like most? Is there anything confusing about any of them? Can you see any problems/confusing situations arising with any of these options?

Option 1

contract C {
  state Start {
    transaction t(money m) {
      this <- S1{m1 = m}
          then toS2();
    }
  }

  state S1 {
    money m1;

    transaction toS2() {
      this <- S2{m2 = m1};
    }
  }

  state S2 {
    money m2;
  }
}

Option 2

contract C {
  state Start {
    transaction t(money m) {
      ->S1(m)
    }
  }

  state S1 {
    money m1;
    S1(money m) { 
      m1 = m;
      ->S2();
    }
  }

  state S2 {
    money m2;
    S2(money m) { 
      m2 = m;
    }
  }
}

Option 3

contract C {
  state Start {
    transaction t(money m) {
      ->S1({m1 = m})
      in S1 {
        ->S2({m2 = m1})
      }
    }
  }

  state S1 {
    money m1;
  }

  state S2 {
    money m2;
  }
}