# 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.