├── .DS_Store ├── .deepsource.toml ├── .gitignore ├── README.md ├── app.py ├── app ├── __init__.py ├── __init__.pyc ├── templates │ ├── base.html │ └── index.html ├── views.py └── views.pyc ├── reference-paper └── Blockchain_Voting_System20200318-112191-yzyxvw-with-cover-page-v2.pdf ├── requirements.txt ├── screenshots ├── .DS_Store ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── block.png ├── hash_block.png ├── hash_function.png ├── purposed_system.png └── structure.png └── service.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/.DS_Store -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | test_patterns = [ 4 | 5 | ] 6 | 7 | exclude_patterns = [ 8 | 9 | ] 10 | 11 | [[analyzers]] 12 | name = 'python' 13 | enabled = true 14 | runtime_version = '3.x.x' 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | **/*.pyc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # E-voting-system-using-blockchain-and-python 2 | 3 | ## Outline 4 | 1. Reference Research Paper 5 | 1. Abstract 6 | 2. Introduction 7 | 3. Blockchain 8 | 4. Ourposed System 9 | 5. Conclusion 10 | 2. Implementaiton of Blockchain in E-voting system 11 | 1. About application 12 | 2. Structure of Blockchain 13 | 3. Chain the blocks 14 | 4. Blockchain Proof of work 15 | 5. Add blocks to the chain 16 | 6. Mining 17 | 3. Instructions to run application 18 | 4. References 19 | 20 | ## 1. Reference Research Paper 21 | This project is based on the concept of research paper which was published in International Journal of Network Security & Its Applications (IJNSA) entitled **"A CONCEPTUAL SECURE BLOCKCHAIN- BASED ELECTRONIC VOTING SYSTEM"** by Ahmed Ben Ayed 22 | 23 | ### Review, Summary of **"A Conceptual Secure Blockchain-based Electronic Voting System"** 24 | [Paper Link](https://aircconline.com/ijnsa/V9N3/9317ijnsa01.pdf) 25 | OR 26 | [Researchgate] (https://www.researchgate.net/publication/341498272_A_CONCEPTUAL_SECURE_BLOCKCHAIN-BASED_ELECTRONIC_VOTING_SYSTEM) 27 | OR 28 | [This repository] ((https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/reference-paper/Blockchain_Voting_System20200318-112191-yzyxvw-with-cover-page-v2.pdf)) 29 | 30 | #### Abstract 31 | This paper support the open source Blockchain technology to propose a design for a new electronic voting system that could be used in local or national elections. 32 | 33 | #### Introduction 34 | An e-Voting system has to have heightened security in order make sure it is available to voters but protected against outside influences changing votes from being cast, or keep a voter’s ballot from being tampered with. Many electronic voting systems rely on to hide the identity of voters. However, this technique does not provide total anonymity or integrity since many intelligence agencies around the world control different parts of the Internet which can allow them to identify or intercept votes. 35 | 36 | #### Blockchain 37 | Blockchain was first introduced by Satoshi Nakamoto (a pseudonym), who proposed a peer-to-peer payment system that allows cash transactions through the Internet without relying on trust or the need for a financial institution. 38 | 39 | Blockchain is an ordered data structure that contains blocks of transactions. Each block in the chain is linked to the previous block in the chain. The first block in the chain is referred to as the foundation of the stack. Each new block created gets layered on top of the previous block to form a stack called a Blockchain. 40 | 41 | 42 | All of the magic lies in the way this data is stored and added to the blockchain. A blockchain is essentially a linked-list containing ordered-data, with some constraints like below; 43 | 44 | * Blocks can't be modified once added; in other words, it is "append-only." 45 | * There are specific rules for appending data to it. 46 | * It's distributed in architecture. 47 | * Enforcing these constraints yields some highly desirable characteristics: 48 | 49 | * Immutability and durability of data 50 | * No single point of control or failure 51 | * A verifiable audit trail of the order in which data was added 52 | 53 | Each block in the stack is identified by a hash placed on the header. This hash is generated using the Secure Hash Algorithm (SHA-256) to generate an almost idiosyncratic fixed-size 256-bit hash. 54 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/hash_function.png) 55 | 56 | Each header contains information that links a block to its previous block in the chain, which creates a chain linked to the very first block ever created, which is referred to as the foundation. The primary identifier of each block is the encrypted hash in its header. A digital fingerprint that was made combining two types of information: the information concerning the new block created, as well as the previous block in the chainAs soon as a block is created, it is sent over to the Blockchain. The system will keep an eye on incoming blocks and continuously update the chain when new blocks arrive. 57 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/hash_block.png) 58 | 59 | #### Purposed System 60 | * Authentication: Only people already registered to vote can cast a vote. Our system will not 61 | support a registration process. Registration usually requires verification of certain information 62 | and documents to comply with current laws, which could not be done online in a secure manner. 63 | Therefore, the system should be able to verify voters’ identities against a previously verified 64 | database, and then let them vote only once. 65 | * Anonymity: The e-Voting system should not allow any links between voters’ identities and 66 | ballots. The voter has to remain anonymous during and after the election. 67 | * Accuracy: Votes must be accurate; every vote should be counted, and can’t be changed, 68 | duplicated or removed. 69 | * Verifiability: The system should be verifiable to make sure all votes are counted correctly. 70 | Beside the main requirement, our solution supports mobility, flexibility, and efficiency. However, 71 | we will limit this paper’s discussion to the four main requirements. 72 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/purposed_system.png) 73 | 74 | To ensure that the system is secure, the block will contain the previous voter’s information. If any of the blocks were compromised, then it would be easy to find out since all blocks are connected to each other. The Blockchain is decentralized and cannot be corrupted; no single point of failure exists. The Blockchain is where the actual voting takes place. The user’s vote gets sent to one of the nodes on the system, and the node then adds the vote to the Blockchain. The voting system will have a node in each district to ensure the system is decentralized. 75 | 76 | #### CONCLUSION 77 | This paper proposed an electronic voting system based on the Blockchain technology. The Blockchain will be publicly verifiable and distributed in a way that no one will be able to corrupt it. 78 | 79 | 80 |
81 | 82 | # Implementaiton of Blockchain in E-voting system 83 | 84 | ## About Applicaiton 85 | Let us briefly define the scope of our mini-application. The goal is to build an application that allows Voter to vote for the party they want with their Voter ID. One voter can only vote one time with their Unique Voter ID. Since the voted information will be stored on the blockchain, it'll be immutable and permanent. Users will interact with the application via a simple web interface. 86 | 87 | We'll follow a bottom-up approach to implement things. Let's begin by defining the structure of the data that we'll store in the blockchain. Three essential elements will identify a post (message posted by any user on our application): 88 | 89 | * voter_id (Voter with their voter ID) 90 | * party (Political parties, Leader) 91 | * timestamp 92 | 93 | We'll be storing data in our blockchain in a format that's widely used: JSON. Here's what a post stored in blockchain will look like: 94 | 95 | ``` 96 | "transactions": [ 97 | { 98 | "voter_id": "VOID001", 99 | "party": "Democratic Party", 100 | "timestamp": 1649571086.02753 101 | } 102 | ], 103 | ``` 104 | 105 | The transactions are packed into blocks. A block can contain one or many transactions. The blocks containing the transactions are generated frequently and added to the blockchain. Because there can be multiple blocks, each block should have a unique id: 106 | ``` 107 | class Block: 108 | def __init__(self, index, transactions, timestamp, previous_hash, nonce=0): 109 | self.index = index 110 | self.transactions = transactions 111 | self.timestamp = timestamp 112 | self.previous_hash = previous_hash 113 | self.nonce = nonce 114 | ``` 115 | 116 | ### Structure of Blockchain 117 | 118 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/structure.png) 119 | ### 1. Digital fingerprints to the blocks 120 | We'd like to prevent any kind of tampering in the data stored inside the block, and detection is the first step to that. To detect if the data in the block is tampered, we can use cryptographic hash functions. 121 | 122 | A hash function is a function that takes data of any size and produces data of a fixed size from it (called hash), which is generally used to identify the input. This project used sha256() hash function. We'll store the hash of the block in a field inside our Block object, and it'll act like a digital fingerprint (or signature) of data contained in it: 123 | ``` 124 | def compute_hash(self): 125 | """ 126 | A function that return the hash of the block contents. 127 | """ 128 | block_string = json.dumps(self.__dict__, sort_keys=True) 129 | return sha256(block_string.encode()).hexdigest() 130 | ``` 131 | ### 2. Chain the blocks 132 | We need a mechanism to make sure that any change in the previous blocks invalidates the entire chain. The Bitcoin way to do this is creating dependency among consecutive blocks by chaining them with the hash of block immediately previous to them. By chaining here, we mean to include the hash of the previous block in the current block in a new field called previous_hash. 133 | 134 | Okay, if every block is linked to the previous block by the previous_hash field, what about the very first block? The very first block is called the genesis block and can be generated either manually or by some unique logic. Let's add the previous_hash field to the Block class and implement the initial structure of our Blockchain class. 135 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/block.png) 136 | Now, if the content of any of the previous blocks changes, 137 | 138 | * The hash of that previous block would change. 139 | * This will lead to a mismatch with the previous_hash field in the next block. 140 | * Since the input data to compute the hash of any block also consists of the previous_hash field, the hash of the next block will also change. 141 | Ultimately, the entire chain following the replaced block is invalidated, and the only way to fix it is to recompute the entire chain. 142 | 143 | ### 3. Blockchain Proof of work 144 | Proof of Work(PoW) is the original consensus algorithm in a blockchain network. The algorithm is used to confirm the transaction and creates a new block to the chain. In this algorithm, miners (a group of people) compete against each other to complete the transaction on the network. The process of competing against each other is called mining. As soon as miners successfully created a valid block, he gets rewarded. The most famous application of Proof of Work(PoW) is Bitcoin. 145 | 146 | If we change the previous block, we can re-compute the hashes of all the following blocks quite easily and create a different valid blockchain. To prevent this, we will now exploit the asymmetry in efforts of hash functions that we discussed previously to make the task of calculating the hash difficult and random. Here's how we do this. Instead of accepting any hash for the block, we add some constraint to it. Let's add a constraint that our hash should start with "n leading zeroes" where n can be any positive integer. 147 | 148 | We know that unless we change the data of the block, the hash is not going to change, and of course, we don't want to change existing data. So, what do we do? Simple! We'll add some dummy data that we can change. Let's introduce a new field in our block called nonce. A nonce is a number that we'll keep on changing until we get a hash that satisfies our constraint. The nonce satisfying the constraint serves as proof that some computation has been performed. The number of zeroes specified in the constraint decides the "difficulty" of our Proof of Work algorithm (more the number of zeroes, harder it is to figure out the nonce). 149 | 150 | ### 4. Add blocks to the chain 151 | To add a block to the chain, we'll first have to verify that, 152 | 153 | * The data is untampered i.e., the Proof of Work provided is correct 154 | * The order of transactions is preserved i.e., the previous_hash field of the block to be added points to the hash of the latest block in our chain. 155 | 156 | ### 5. Mining 157 | Mining, in the context of blockchain technology, is the process of adding transactions to the large distributed public ledger of existing transactions, known as the blockchain. The term is best known for its association with bitcoin, though other technologies using the blockcahin employ mining. 158 | 159 | The transactions will be initially stored as a pool of unconfirmed transactions. The process of putting the unconfirmed transactions in a block and computing Proof of Work is known as the mining of blocks. Once the nonce satisfying our constraints is figured out, we can say that a block has been mined, and it can be put into the chain. 160 | 161 | ## Instructions to run the application 162 | 163 | Clone the project, 164 | 165 | ```sh 166 | $ git clone https://github.com/adhikarir/E-voting-system-using-blockchain-and-python.git 167 | ``` 168 | 169 | Install the dependencies, 170 | 171 | ```sh 172 | $ cd E-voting-system-using-blockchain-and-python 173 | $ pip install -r requirements.txt 174 | ``` 175 | 176 | Start a blockchain node server, 177 | 178 | ```sh 179 | # Windows users can follow this: https://flask.palletsprojects.com/en/1.1.x/cli/#application-discovery 180 | $ export FLASK_APP=service.py 181 | $ flask run --port 8000 182 | or 183 | python3 -m flask run --port 8000 184 | ``` 185 | 186 | One instance of our blockchain node is now up and running at port 8000. 187 | 188 | 189 | Run the application on a different terminal session, 190 | 191 | ```sh 192 | $ python app.py 193 | ``` 194 | 195 | The application should be up and running at [http://localhost:5000](http://localhost:5000). 196 | 197 | Here are a few screenshots 198 | 199 | ##### 1. Posting vote 200 | 201 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/1.png) 202 | 203 | ##### 2. Requesting the node to mine 204 | 205 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/2.png) 206 | 207 | ##### 3. Resyncing with the chain for updated data 208 | 209 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/3.png) 210 | 211 | ##### 4. Chain of the transaction 212 | 213 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/4.png) 214 | 215 | ##### 5. App screenshot 216 | 217 | ![image.png](https://github.com/adhikarir/E-voting-system-using-blockchain-and-python/blob/master/screenshots/5.png) 218 | 219 | To play around by spinning off multiple custom nodes, use the `register_with/` endpoint to register a new node. 220 | 221 | Here's a sample scenario that you might wanna try, 222 | 223 | ```sh 224 | # Make sure you set the FLASK_APP environment variable to service.py before running these nodes 225 | # already running 226 | $ flask run --port 8000 or python3 -m flask run --port 8000& 227 | # spinning up new nodes 228 | $ flask run --port 8001 & 229 | $ flask run --port 8002 & 230 | ``` 231 | You can use the following cURL requests to register the nodes at port 8001 and 8002 with the already running 8000. 232 | ``` 233 | curl -X POST \ 234 | http://127.0.0.1:8001/register_with \ 235 | -H 'Content-Type: application/json' \ 236 | -d '{"node_address": "http://127.0.0.1:8000"}' 237 | ``` 238 | ``` 239 | curl -X POST \ 240 | http://127.0.0.1:8002/register_with \ 241 | -H 'Content-Type: application/json' \ 242 | -d '{"node_address": "http://127.0.0.1:8000"}' 243 | ``` 244 | 245 | This will make the node at port 8000 aware of the nodes at port 8001 and 8002, and make the newer nodes sync the chain with the node 8000, so that they are able to actively participate in the mining process post registration. 246 | 247 | To update the node with which the frontend application syncs (default is localhost port 8000), change `CONNECTED_SERVICE_ADDRESS` field in the [views.py](/app/views.py) file. 248 | 249 | Once you do all this, you can run the application, create transactions (post vote via the web inteface), and once you mine the transactions, all the nodes in the network will update the chain. The chain of the nodes can also be inspected by inovking `/chain` endpoint using cURL. 250 | 251 | ```sh 252 | $ curl -X GET http://localhost:8001/chain 253 | $ curl -X GET http://localhost:8002/chain 254 | ``` 255 | 256 | ## References 257 | 1. https://aircconline.com/ijnsa/V9N3/9317ijnsa01.pdf 258 | 2. https://www.geeksforgeeks.org/decentralized-voting-system-using-blockchain/ 259 | 3. https://www.javatpoint.com/blockchain-proof-of-work 260 | 4. https://github.com/satwikkansal/python_blockchain_app/tree/ibm_blockchain_post 261 | 5. https://www.ibm.com/topics/what-is-blockchain 262 | 6. https://en.wikipedia.org/wiki/Blockchain 263 | 7. https://github.com/Abhiramborige/Online-Voting-Using-Blockchain 264 | 265 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | 3 | app.secret_key = '6dbf23122cb5046cc5c0c1b245c75f8e43c59ca8ffeac292715e5078e631d0c9' 4 | app.config['SESSION_TYPE'] = 'filesystem' 5 | 6 | app.run(debug=True, port=5000) 7 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | from app import views -------------------------------------------------------------------------------- /app/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/app/__init__.pyc -------------------------------------------------------------------------------- /app/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 |

{{ title }}

9 |
10 | {% with messages = get_flashed_messages(with_categories=true) %} 11 | {% if messages %} 12 |
13 | 14 | {% for category, message in messages %} 15 | {% if category=='error'%} 16 |
  • {{ message }}
  • 17 | {% else %} 18 |
  • {{ message }}
  • 19 | {% endif %} 20 | 21 | {% endfor %} 22 |
    23 | 24 | {% endif %} 25 | {% endwith %} 26 | {% block content %}{% endblock %} 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "base.html" %} 3 | 4 | {% block content %} 5 |
    6 |
    7 |
    8 | 9 | 10 |
    11 | 12 | 13 | 16 | 23 | 24 | 25 | 28 | 31 | 32 | 33 | 34 | 37 | 38 |
    14 | 15 | 22 |
    26 | 27 | 29 | 30 |
    35 | 36 |
    39 |
    40 | 41 |
    42 |
    43 | 44 | 45 | 46 | 47 | 48 | {% for voter_id in voter_ids %} 49 | 50 | 53 | 54 | {% endfor %} 55 |
    Sample Voter ID
    51 | {{voter_id}} 52 |
    56 |
    57 |
    58 |
    59 |
    60 |
    61 | 62 | 63 | 64 |
    65 |
    66 | 67 | 68 | 69 |
    70 | 71 |
    72 |

    Result Detail

    73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | {% for post in posts %} 81 | 82 | 83 | 84 | 85 | 86 | {% endfor %} 87 |
    Voter IDPolitical Party NameVoted Time
    {{post.voter_id}}{{post.party}}{{readable_time(post.timestamp)}}
    88 |
    89 | 90 |
    91 |

    Result Summary

    92 | 93 | 94 | 95 | 96 | 97 | 98 | {% for p in political_parties %} 99 | 100 | 101 | 102 | 103 | {% endfor %} 104 |
    Political Party NameTotal vote gain
    {{p}}{{vote_gain.count(p)}}
    105 |
    106 | 107 | 108 | 109 | 110 | 111 | 138 |
    139 | {% endblock %} 140 | -------------------------------------------------------------------------------- /app/views.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | 4 | import requests 5 | from flask import render_template, redirect, request 6 | from flask import flash 7 | from app import app 8 | 9 | # The node with which our application interacts, there can be multiple 10 | # such nodes as well. 11 | CONNECTED_SERVICE_ADDRESS = "http://127.0.0.1:8000" 12 | POLITICAL_PARTIES = ["Democratic Party","Republican Party","Socialist party"] 13 | VOTER_IDS=[ 14 | 'VOID001','VOID002','VOID003', 15 | 'VOID004','VOID005','VOID006', 16 | 'VOID007','VOID008','VOID009', 17 | 'VOID010','VOID011','VOID012', 18 | 'VOID013','VOID014','VOID015'] 19 | 20 | vote_check=[] 21 | 22 | posts = [] 23 | 24 | 25 | def fetch_posts(): 26 | """ 27 | Function to fetch the chain from a blockchain node, parse the 28 | data and store it locally. 29 | """ 30 | get_chain_address = "{}/chain".format(CONNECTED_SERVICE_ADDRESS) 31 | response = requests.get(get_chain_address) 32 | if response.status_code == 200: 33 | content = [] 34 | vote_count = [] 35 | chain = json.loads(response.content) 36 | for block in chain["chain"]: 37 | for tx in block["transactions"]: 38 | tx["index"] = block["index"] 39 | tx["hash"] = block["previous_hash"] 40 | content.append(tx) 41 | 42 | 43 | global posts 44 | posts = sorted(content, key=lambda k: k['timestamp'], 45 | reverse=True) 46 | 47 | 48 | @app.route('/') 49 | def index(): 50 | fetch_posts() 51 | 52 | vote_gain = [] 53 | 54 | for post in posts: 55 | vote_gain.append(post["party"]) 56 | 57 | return render_template('index.html', 58 | title='E-voting system ' 59 | 'using Blockchain and python', 60 | posts=posts, 61 | vote_gain=vote_gain, 62 | node_address=CONNECTED_SERVICE_ADDRESS, 63 | readable_time=timestamp_to_string, 64 | political_parties=POLITICAL_PARTIES, 65 | voter_ids=VOTER_IDS) 66 | 67 | 68 | @app.route('/submit', methods=['POST']) 69 | def submit_textarea(): 70 | """ 71 | Endpoint to create a new transaction via our application. 72 | """ 73 | party = request.form["party"] 74 | voter_id = request.form["voter_id"] 75 | 76 | post_object = { 77 | 'voter_id': voter_id, 78 | 'party': party, 79 | } 80 | if voter_id not in VOTER_IDS: 81 | flash('Voter ID invalid, please select voter ID from sample!', 'error') 82 | return redirect('/') 83 | if voter_id in vote_check: 84 | flash('Voter ID ('+voter_id+') already vote, Vote can be done by unique vote ID only once!', 'error') 85 | return redirect('/') 86 | else: 87 | vote_check.append(voter_id) 88 | # Submit a transaction 89 | new_tx_address = "{}/new_transaction".format(CONNECTED_SERVICE_ADDRESS) 90 | 91 | requests.post(new_tx_address, 92 | json=post_object, 93 | headers={'Content-type': 'application/json'}) 94 | # print(vote_check) 95 | flash('Voted to '+party+' successfully!', 'success') 96 | return redirect('/') 97 | 98 | 99 | def timestamp_to_string(epoch_time): 100 | return datetime.datetime.fromtimestamp(epoch_time).strftime('%Y-%m-%d %H:%M') 101 | -------------------------------------------------------------------------------- /app/views.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/app/views.pyc -------------------------------------------------------------------------------- /reference-paper/Blockchain_Voting_System20200318-112191-yzyxvw-with-cover-page-v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/reference-paper/Blockchain_Voting_System20200318-112191-yzyxvw-with-cover-page-v2.pdf -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask~=1.1 2 | requests~=2.22 3 | -------------------------------------------------------------------------------- /screenshots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/.DS_Store -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/2.png -------------------------------------------------------------------------------- /screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/3.png -------------------------------------------------------------------------------- /screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/4.png -------------------------------------------------------------------------------- /screenshots/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/5.png -------------------------------------------------------------------------------- /screenshots/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/block.png -------------------------------------------------------------------------------- /screenshots/hash_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/hash_block.png -------------------------------------------------------------------------------- /screenshots/hash_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/hash_function.png -------------------------------------------------------------------------------- /screenshots/purposed_system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/purposed_system.png -------------------------------------------------------------------------------- /screenshots/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramesh-adhikari/E-voting-system-using-blockchain-and-python/df204dede839fe6464ad8c66ed06dee5db6968b4/screenshots/structure.png -------------------------------------------------------------------------------- /service.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | import json 3 | import time 4 | 5 | from flask import Flask, request 6 | import requests 7 | 8 | 9 | class Block: 10 | def __init__(self, index, transactions, timestamp, previous_hash, nonce=0): 11 | self.index = index 12 | self.transactions = transactions 13 | self.timestamp = timestamp 14 | self.previous_hash = previous_hash 15 | self.nonce = nonce 16 | 17 | def compute_hash(self): 18 | """ 19 | A function that return the hash of the block contents. 20 | """ 21 | block_string = json.dumps(self.__dict__, sort_keys=True) 22 | return sha256(block_string.encode()).hexdigest() 23 | 24 | 25 | class Blockchain: 26 | # difficulty of our PoW algorithm 27 | difficulty = 2 28 | 29 | def __init__(self): 30 | self.unconfirmed_transactions = [] 31 | self.chain = [] 32 | 33 | def create_genesis_block(self): 34 | """ 35 | A function to generate genesis block and appends it to 36 | the chain. The block has index 0, previous_hash as 0, and 37 | a valid hash. 38 | """ 39 | genesis_block = Block(0, [], 0, "0") 40 | genesis_block.hash = genesis_block.compute_hash() 41 | self.chain.append(genesis_block) 42 | 43 | @property 44 | def last_block(self): 45 | return self.chain[-1] 46 | 47 | def add_block(self, block, proof): 48 | """ 49 | A function that adds the block to the chain after verification. 50 | Verification includes: 51 | * Checking if the proof is valid. 52 | * The previous_hash referred in the block and the hash of latest block 53 | in the chain match. 54 | """ 55 | previous_hash = self.last_block.hash 56 | 57 | if previous_hash != block.previous_hash: 58 | return False 59 | 60 | if not Blockchain.is_valid_proof(block, proof): 61 | return False 62 | 63 | block.hash = proof 64 | self.chain.append(block) 65 | return True 66 | 67 | @staticmethod 68 | def proof_of_work(block): 69 | """ 70 | Function that tries different values of nonce to get a hash 71 | that satisfies our difficulty criteria. 72 | """ 73 | block.nonce = 0 74 | 75 | computed_hash = block.compute_hash() 76 | while not computed_hash.startswith('0' * Blockchain.difficulty): 77 | block.nonce += 1 78 | computed_hash = block.compute_hash() 79 | 80 | return computed_hash 81 | 82 | def add_new_transaction(self, transaction): 83 | self.unconfirmed_transactions.append(transaction) 84 | 85 | @classmethod 86 | def is_valid_proof(cls, block, block_hash): 87 | """ 88 | Check if block_hash is valid hash of block and satisfies 89 | the difficulty criteria. 90 | """ 91 | return (block_hash.startswith('0' * Blockchain.difficulty) and 92 | block_hash == block.compute_hash()) 93 | 94 | @classmethod 95 | def check_chain_validity(cls, chain): 96 | result = True 97 | previous_hash = "0" 98 | 99 | for block in chain: 100 | block_hash = block.hash 101 | # remove the hash field to recompute the hash again 102 | # using `compute_hash` method. 103 | delattr(block, "hash") 104 | 105 | if not cls.is_valid_proof(block, block_hash) or \ 106 | previous_hash != block.previous_hash: 107 | result = False 108 | break 109 | 110 | block.hash, previous_hash = block_hash, block_hash 111 | 112 | return result 113 | 114 | def mine(self): 115 | """ 116 | This function serves as an interface to add the pending 117 | transactions to the blockchain by adding them to the block 118 | and figuring out Proof Of Work. 119 | """ 120 | if not self.unconfirmed_transactions: 121 | return False 122 | 123 | last_block = self.last_block 124 | 125 | new_block = Block(index=last_block.index + 1, 126 | transactions=self.unconfirmed_transactions, 127 | timestamp=time.time(), 128 | previous_hash=last_block.hash) 129 | 130 | proof = self.proof_of_work(new_block) 131 | self.add_block(new_block, proof) 132 | 133 | self.unconfirmed_transactions = [] 134 | 135 | return True 136 | 137 | 138 | app = Flask(__name__) 139 | 140 | # the node's copy of blockchain 141 | blockchain = Blockchain() 142 | blockchain.create_genesis_block() 143 | 144 | # the address to other participating members of the network 145 | peers = set() 146 | 147 | 148 | # endpoint to submit a new transaction. This will be used by 149 | # our application to add new data (posts) to the blockchain 150 | @app.route('/new_transaction', methods=['POST']) 151 | def new_transaction(): 152 | tx_data = request.get_json() 153 | required_fields = ["voter_id", "party"] 154 | 155 | for field in required_fields: 156 | if not tx_data.get(field): 157 | return "Invalid transaction data", 404 158 | 159 | tx_data["timestamp"] = time.time() 160 | 161 | blockchain.add_new_transaction(tx_data) 162 | 163 | return "Success", 201 164 | 165 | 166 | # endpoint to return the node's copy of the chain. 167 | # Our application will be using this endpoint to query 168 | # all the posts to display. 169 | @app.route('/chain', methods=['GET']) 170 | def get_chain(): 171 | chain_data = [] 172 | for block in blockchain.chain: 173 | chain_data.append(block.__dict__) 174 | return json.dumps({"length": len(chain_data), 175 | "chain": chain_data, 176 | "peers": list(peers)}) 177 | 178 | 179 | # endpoint to request the node to mine the unconfirmed 180 | # transactions (if any). We'll be using it to initiate 181 | # a command to mine from our application itself. 182 | @app.route('/mine', methods=['GET']) 183 | def mine_unconfirmed_transactions(): 184 | result = blockchain.mine() 185 | if not result: 186 | return "No transactions to mine" 187 | else: 188 | # Making sure we have the longest chain before announcing to the network 189 | chain_length = len(blockchain.chain) 190 | consensus() 191 | if chain_length == len(blockchain.chain): 192 | # announce the recently mined block to the network 193 | announce_new_block(blockchain.last_block) 194 | return "Block #{} is mined.".format(blockchain.last_block.index) 195 | 196 | 197 | # endpoint to add new peers to the network. 198 | @app.route('/register_node', methods=['POST']) 199 | def register_new_peers(): 200 | node_address = request.get_json()["node_address"] 201 | if not node_address: 202 | return "Invalid data", 400 203 | 204 | # Add the node to the peer list 205 | peers.add(node_address) 206 | 207 | # Return the consensus blockchain to the newly registered node 208 | # so that he can sync 209 | return get_chain() 210 | 211 | 212 | @app.route('/register_with', methods=['POST']) 213 | def register_with_existing_node(): 214 | """ 215 | Internally calls the `register_node` endpoint to 216 | register current node with the node specified in the 217 | request, and sync the blockchain as well as peer data. 218 | """ 219 | node_address = request.get_json()["node_address"] 220 | if not node_address: 221 | return "Invalid data", 400 222 | 223 | data = {"node_address": request.host_url} 224 | headers = {'Content-Type': "application/json"} 225 | 226 | # Make a request to register with remote node and obtain information 227 | response = requests.post(node_address + "/register_node", 228 | data=json.dumps(data), headers=headers) 229 | 230 | if response.status_code == 200: 231 | global blockchain 232 | global peers 233 | # update chain and the peers 234 | chain_dump = response.json()['chain'] 235 | blockchain = create_chain_from_dump(chain_dump) 236 | peers.update(response.json()['peers']) 237 | return "Registration successful", 200 238 | else: 239 | # if something goes wrong, pass it on to the API response 240 | return response.content, response.status_code 241 | 242 | 243 | def create_chain_from_dump(chain_dump): 244 | generated_blockchain = Blockchain() 245 | generated_blockchain.create_genesis_block() 246 | for idx, block_data in enumerate(chain_dump): 247 | if idx == 0: 248 | continue # skip genesis block 249 | block = Block(block_data["index"], 250 | block_data["transactions"], 251 | block_data["timestamp"], 252 | block_data["previous_hash"], 253 | block_data["nonce"]) 254 | proof = block_data['hash'] 255 | added = generated_blockchain.add_block(block, proof) 256 | if not added: 257 | raise Exception("The chain dump is tampered!!") 258 | return generated_blockchain 259 | 260 | 261 | # endpoint to add a block mined by someone else to 262 | # the node's chain. The block is first verified by the node 263 | # and then added to the chain. 264 | @app.route('/add_block', methods=['POST']) 265 | def verify_and_add_block(): 266 | block_data = request.get_json() 267 | block = Block(block_data["index"], 268 | block_data["transactions"], 269 | block_data["timestamp"], 270 | block_data["previous_hash"], 271 | block_data["nonce"]) 272 | 273 | proof = block_data['hash'] 274 | added = blockchain.add_block(block, proof) 275 | 276 | if not added: 277 | return "The block was discarded by the node", 400 278 | 279 | return "Block added to the chain", 201 280 | 281 | 282 | # endpoint to query unconfirmed transactions 283 | @app.route('/pending_tx') 284 | def get_pending_tx(): 285 | return json.dumps(blockchain.unconfirmed_transactions) 286 | 287 | 288 | def consensus(): 289 | """ 290 | Our naive consnsus algorithm. If a longer valid chain is 291 | found, our chain is replaced with it. 292 | """ 293 | global blockchain 294 | 295 | longest_chain = None 296 | current_len = len(blockchain.chain) 297 | 298 | for node in peers: 299 | response = requests.get('{}chain'.format(node)) 300 | length = response.json()['length'] 301 | chain = response.json()['chain'] 302 | if length > current_len and blockchain.check_chain_validity(chain): 303 | current_len = length 304 | longest_chain = chain 305 | 306 | if longest_chain: 307 | blockchain = longest_chain 308 | return True 309 | 310 | return False 311 | 312 | 313 | def announce_new_block(block): 314 | """ 315 | A function to announce to the network once a block has been mined. 316 | Other blocks can simply verify the proof of work and add it to their 317 | respective chains. 318 | """ 319 | for peer in peers: 320 | url = "{}add_block".format(peer) 321 | headers = {'Content-Type': "application/json"} 322 | requests.post(url, 323 | data=json.dumps(block.__dict__, sort_keys=True), 324 | headers=headers) 325 | 326 | # Uncomment this line if you want to specify the port number in the code 327 | #app.run(debug=True, port=8000) 328 | --------------------------------------------------------------------------------