# Final Project--Voting via Blockchain--DESIGN.md
### Date: 5/17/21
## Rough Requirements
We are making a music voting mechanism that allows users to queue up
a specific song to be played next.
For our current application, the tracker will double as the synchronization
node--i.e. it will be the one which tallies all votes and maintains
election cycles.
#### The Tracker
Shall:
1. Keep track of all nodes who've joined the network and are active
while keeping track of each node's public key as well and their willingness to mine.
It should distribute this mapping of nodes->keys to each new
client upon establishing a successful connection.
Keep track of miners and clients separately, but send all of
these nodes to each client for a new connection.
2. Operate on an "election" cycle (specified at server startup through
config), upon each cycle, the tracker will:
- Wait until one of the following occurs:
* PERCENT_REQUIRED of votes is met
* TIMEOUT of votes is met (Some large value for infinite wait)
- Once one of the preceding conditions has been met,
- the tracker requests for blockchain copies from all nodes
- tally votes and send the vote tally to all nodes
3. Use blockchain & asymmetric key cryptography for security
- Upon startup, the tracker shall "seed" the blockchain with
an initial block, which it will pass to the first client.
(Only the first client is required since that client
will then broadcast its full chain to all clients which
form a p2p connection with it)
#### The Client
Shall:
1. Generate a public/private key pair for session use
2. Take in a desired tracker hostname & port, establish a connection,
and send its public key to the tracker
3. Read in the peer-to-peer network sent by the tracker, and establish
a connection with (all or some?) of the other nodes in the list
4. Query its neighbor nodes for a copy of their current blockchain,
and keep the copy which is the longest.
5. Provide an interface for the user to input their song choice for
the current cycle, and print out updates from the tracker about
the time left for the current cycle when the user desires. When
the song has been decided for a cycle, print the total tally
received from the tracker.
- Once the user has given input, parse the user's vote and package
it into a block of our blockchain. Broadcast that block to all
nodes connected before starting to mine (to ensure as synchronous
changes as possible).
6. Keep threads open for:
- listening for new p2p connections
- listening for peer updates (new blocks & block mining success)
7. As noted above, constantly listen for new blocks from peers. Given
the data at a block, make an informed choice (i.e. with
preconfigured settings) about whether to add this block to our
blockchain (i.e. is it an orphaned block? stale block? or the
active branch?)
8. Allow for both mining and non-mining clients. A non-mining
client could be used by voters to be able to submit votes without
having to contribute to the mining effort.
- Mining incentivized through the ability to list a specific song by name
#### Assumptions
The public/private key generated by a client will not change for
that session. In the future/for a real voting application,
in order to authenticate users, we will rely on a certificate
system/existing public key infrastructure (i.e. voter registration
mechanisms currently in place for public office elections). For
the purposes of this application, we will allow any node which
joins the network to vote.
We should safely assume that the tracker/server program will
always be running before the clients are started. If not,
the clients should cleanly fall out of the tcp connection
attempt.
For this application, we can safely assume that all nodes in
the network will submit a vote within a reasonable time
frame. Once all votes have been cast for the cycle, the tracker
will be notified (in some way) that the cycle is over (depending
on startup configuration for the server).
# Design Specifications
## Assumptions
Assumption:
* network stability/atomic connection time
(if a node recieves data, it can assume it's safe to send to network)
## User Interface
We'll have a GUI which fires up the application backend, while
listening for user votes in the form of `yes/no`. Only miners will be
able to use song tokens to introduce new songs of their choosing to the
queue, held by the tracker/server.
The output will generally be in the form of vote tallies sent per
election cycle.
(In theory, this section shouldn't reference anything about the blockchain. The blockchain is a lower-level building block upon which this application (and the protocol that outlines how data will be transferred) is all handled at the lower level like how TCP abstracts away the "reliable delivery" aspect of network socket communication.)
## Inputs and outputs
Similar to the user interface, we should describe how data is input into the client/tracker programs, including:
From the command line, the client will be run with:
`./python3 client.py [tracker_address] [socket_port] [mining mode] [key_file]`
Where:
- `tracker_address` is the ip address of the tracker/server
- `socket_port` is the port # of the tracker/server program
- `mining mode` indicates whether the client is willing to mine blocks and whether or not the client is able to request specific songs
Per the assignment requirement, we will use the port numbers assigned
to us for lab 4:
- 60000-60030 (primary)
- 60899-60929
- 60837-60867
- 60868-60898
- 60062-60092
The tracker will be run with:
`./python3 tracker.py [hash_padding] [cycle_config] [timeout]`
Where:
- `hash_padding` indicates the number of bits to set to 0 for mining
- `cycle_config`
- `timeout` is the maximum amount of time, in ms, which the tracker will wait for a response from peers
## Functional decomposition into modules
Cryptography module: contains submodules which handle
RSA public/private key encryption infrastructure
available for us to use. See `Crypto.PublicKey` for the
module in Python.
Hashing module: SHA-256 hashing function. In Python, it's
in `hashlib`
#### Our own Modules
*Blockchain Module*
```
See Data Structure for Blockchain
```
*Voting/Protocol Module*
Includes functions to verify blocks based on a current
blockchain, submit votes to the blockchain, running a client, data
propagation in the network, and running a tracker.
```
# Verify the data in a block using the given node ID
verify(Block, Node ID/Public Key Map)
```
*Mining Module*
A set of functions which can be called by the
client application to verify transactions and add them to the blockchain.
Our protocol will require proof-of-work to be able to add to the blockchain.
```
mine(block)
```
**Primary Process Types**:
*Server/Tracker Application Module*
```
# Maintain network info
# If node joins, update network and send info to node
# If node leaves, update network
```
*Client Application Module*
```
# Main client program
# Handle Mining if needed
# Handle user inputs/votes
```
## Pseudo code (plain English-like language) for logic/algorithmic flow
A user logs onto the application by telling the tracker they have joined and what their public key is and what port they will listen for new connections on. The tracker tells them all the other users and their respective public keys and ports
Every user that joined before will have the job of opening a TCP connection with the new client. Therefore for this toy application we create an entirely connected topology with TCP connections
We need to files to handle this P2Pclient.py and P2Ptracker.py
P2P client can then send a message to all of the other nodes and also communicate with the tracker about leaving.
*Client Module*
```
Parse command line arguments
Establish connection to tracker
Create p2p connections with peers/neighbors from tracker
Ask for the blockchain from all neighbors
While client is running:
Continually listen for:
- Updates to the chain
- New neighbors
- Results of votes from tracker
- Valid votes to be added to blockchain
If mining:
Mine current data to try to put out a new block
If success:
Flood the block out
```
*Server/Tracker Module*
```
Parse command line inputs
Establish a listening socket
Upon new connection:
Add connection to tracker list
Send client tracker list
Upon quorum or timeout:
Blockchain is verified
Votes are tallied
Verification and results are sent into network
```
## The Protocol (Application-Level)
What will the format of the block data look like?
What does one "vote" look like?
In the block data, an entry will be serialized and deserialized
as part of the blockchain. That way, entries/votes will be
in object form for the program to use as necessary. Message types
will be added as needed in the implementation of the application
protocol.
## The Protocol (Blockchain-Level)
Json (or something similar) will be the primary serialization
and deserialization tool used to transmit the blockchain over
the network.
## Major data structures
We are following a roughly object-oriented model.
*The "BlockChain"*
```
*a data structure here to hold a list of blocks*
*forks are stored as a list of different possible heads for the blockchain*
*the size of the blockchain*
GetChain(neighbors){
Asks all neighbors to send their blockchain over
Verifies each chain and returns the longest valid one
}
SendChain(neighbor){
Upon Request from a neighbor or the tracker, send my current blockchain
}
VerifyChain(){
Recursively call Block.verify and then Entry.verify to verify every block in this chain
Returns True if passes
False if not.
}
```
*Entry*
A specific vote sent by a user using their private key.
```
Data
Public Key
Song Vote
Signature
Functions
sign()
{
generates public key and signature of entry
}
verify()
{
}
write()
```
*Block*
A collection of Entries.
```
//Data
Block ID
Nonce
Entries (The Data)
A link to the previous block
//Functions
hash()
{
SHA256 hash function
}
verify()
{
Bitshift self.hash() to isolate desired HASH_PADDING, and check
this is 0
}
mine(Data, numOfZero)
{
generate nonce values until self.verify() == TRUE
}
//Serialize the list using pickle,
//ignoring any pointers and local data
serialize()
{
iterate through list (recursive)
}
write()
{
writes data to entries
}
```
*Client*
```
JoinChain(Tracker hostname and port number)
{
Creates a TCP connection with a given tracker
by sending local ip and portnumber and public key
Receives a list of neighbors from the Tracker
Opens a TCP with each of them and keeps track of that connection and their
respective public keys
}
LeaveChain(){
Destroy all created connections and tell the Tracker we are leaving
}
ReceieveVote(){
Listens to a vote from another client.
Add this vote to data to be mined upon if I am a mining client
}
Mine(Nonce){
Calls the block.mine by passing in current votes we have heard and the last nonce we have tried as a starting point. Continually add 1 to nonce until we get a valid block. On completetion sends the finished block to all neighbors.
}
```
*Tracker*
```
AcceptClient(client){
addClient to dictionary of clients
Send this new client all the other connected clients and their respective keys
}
RemoveClient(client){
take client out of dictionary
}
BroadCastTally(){
Calls GetBlockChain, gets the chain
Then calls tally on the chain
Broadcast's the official tally to all clients (who are free to verify on their own)
}
```
## Testing plan
Unit testing will be done for each new function and class.
This will consist of deterministic tests which verify that known inputs
generate correct outputs. This should be done for every non-trivial
function and should be organized per python file.
As miners and the tracker will be running on the Thayer system, we will
test integration of components through interactions on the Thayer
servers. We will conduct input validation, performance testing, and
integration testing on these servers.