Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0010bc3

Browse filesBrowse files
committed
first commit
0 parents  commit 0010bc3
Copy full SHA for 0010bc3

File tree

Expand file treeCollapse file tree

3,216 files changed

+935545
-0
lines changed
Filter options

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree

3,216 files changed

+935545
-0
lines changed

‎.vscode/settings.json

Copy file name to clipboard
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"python.pythonPath": "blockchain-env/bin/python3"
3+
}

‎README.md

Copy file name to clipboard
+86Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# CRYPTOCURRENCY PROTOTYPE.
2+
3+
## CERTAIN REQUIREMENTS.
4+
5+
6+
**Activate the virtual environment**
7+
<br>
8+
This is a requirement because any change in the python module in the system can affect the whole code. A virtual environment will not cause any such problem to the system modules.
9+
```
10+
source blockchain-env/bin/activate
11+
```
12+
13+
**Installing all the requirements**
14+
<br>
15+
All the requirements will be updated in the requirements.txt file hence there will not be any requirement of typing numbers of code.
16+
```
17+
pip3 install -r requirements.txt
18+
```
19+
20+
**Running tests**
21+
<br>
22+
Make sure to activate the virtual environment first. Then later perform these tests.
23+
```
24+
python3 -m pytest backend/tests
25+
```
26+
27+
**Running the app and API**
28+
<br>
29+
Make sure to activate the virtual environment first. Then perform these tests.
30+
```
31+
python3 -m backend.app
32+
```
33+
34+
**Running a peer instance**
35+
<br>
36+
Make sure to activate the virtual environment.
37+
```
38+
export PEER=True && python3 -m backend.app
39+
```
40+
41+
*This will be updated accordingly*
42+
___
43+
## DEVELOPER'S IDEA
44+
My idea is to create a cryptocurrency system which I can utilise for payments inside the college. The idea is to create a full fledged cryptocurrency system with certain nodes and verification. I hope to make teacher's desktops as miners and students as the wallet holders. Teacher's desktop will verify and add the transaction details to the blockchain and on spending some computational power the teacher may recieve some incentive which will be decided during a later period. The value of the currency system will also be decided later on.
45+
___
46+
## DEVELOPER'S NOTES
47+
48+
The notes provided are in chronological order. Even the words written are in chronological order.
49+
<br>
50+
51+
- **Day 1(10/10/2020)**: Created the blockchain module and block module, also we have created the hashing function in the python-blockchain folder. The files are commented for anyone to understand the code.[END OF DAY 1]
52+
53+
- **Day 2(11/10/2020)**: We have updated our modules into packages, and we have put __init__.py function each of the folders. We have split the modules into two categories blockchain and util. Blockchain contains the block and blockchain module. Util contains the other utilities required in the function. We have also set up a virtual environment using the venv command and to activate the virtual environment we have used the shell/terminal command mentioned above in this file.
54+
So to activate the package format we use
55+
```
56+
python3 -m backend.blockchain.block
57+
```
58+
>We don't need any .py extension to the file as it automatically loads all the folders and stuff.
59+
60+
- I have also created some tests using Pytest. Pytest checks all the test cases at once rather than us have to type test cases inside the python file and then later we have to check cases for each of the files. Later I have also included time.asctime() to display the timestamp in form of string.[END OF DAY 2]
61+
62+
- **Day 3(18/10/2020)**: I have created the proof of work system in the Block.py module in the mine_block() method. I also have included certain tests in the test folder. Now I also have created a config.py file which will give the mention of the MINE_RATE. Now I have set the mine rate to 10 seconds. So we have to get the rate to around 10 seconds (4 seconds just for program purposes). Now we have added certain tests which support the proof of work system. Till now there was a hex based proof of work system but we need a binary form of proof of work system.
63+
Now we have implemented a system for conversion of hex to binary and hence the difficulty determination is binary based work now. There is no new shell script other than testing the application.
64+
Extra information is given in the required files.
65+
66+
- PART 2: Now I have implemented conditions required for validation of the block and test condtions in the test_block.py file. These tests will check the conditions necessary to validate a block. Also with the help of the pytest's 'with' keyword, we have been able to validate the require exception without the program crashing. Later we have provided test cases to validate a chain, which is basically validating multiple blocks. One important condition is that we have to validate the genesis block which we didn't do in block validation. Hence this was the extra thing we did in the blockchain validation. More stuff is given in programs as documentation string and as well as in commented blocks. Later we have included some chain texts which will help us setup nodes in the blockchain network. Later I will try to explain the use of REST api's and pubsub layers the best I can because I'm using it for the first time myself.[END OF DAY 3]
67+
68+
- **Day 4(25/10/2020)**: I have now setup Flask which is a python module used to create web applications as well as API. The installation of this module is updated in the requirements.txt file. This will install the required modules in the virtual environment. Then later I have been able to run the application which have helped to run this application as localhost. I have also imported the jsonify class to convert objects into JSON format which can be utilised by any application to read data. But then Blockchain class is not JSON serializable hence we need to provide a method in the blockchain class which does so. I have added a method which will return the string to it's JSON format which is either a dictionary, string, tuple, response instance or a valid callable. This ensures that the text in the blockchain gets jsonified and we will get the proper blockchain output in the JSON format which can be utilised by the application to access it's data. Later I also have setup the mine block route in the app directory's __init__.py file which does the mining method in the server. Later in the day I have installed requests module in python which will help get any peer node the already present blockchain data. This will ensure all the nodes remain upto date in the network.
69+
70+
- **Day 5(14/11/2020)**: Today I began my work with developing a cryptocurrency system in this project. I have started by making a folder for the wallet which has different parameters. A wallet should contain a public key, a private key, transactions and wallet balance. So by python I have created a wallet module (by adding an init file along with the main file.), this features wallet data mentioned above, method for signing transactions as well as verify them. Initially I have imported a UUID module which serves us as a Unique digital identifier, this will help us prevent repeating transactions over the same address. Our method for cryptography is EC(Elliptic cryptography), but soon our team will try to migrate to RSA cryptography. This method is highly complex mathematics and will not be easy to crack the original data once created. I have also updated the requirements.txt file in this folder so that future developers can collaborate into this project by downloading the required files. There are many inbuilt functions in the modules. I have also included a test to verify the wallet data in the tests folder in the backend module.
71+
72+
- Later I have also created a transaction module which facilates the transactions in this cryptocurrency network. This includes the wallet module created and uuid module which provides a unique identifier to the new module. The transactions module contains input structure and output structure which will record and calculate the balance necessities in a wallet. This includes exceeding balance which should result in a failure of transactions. We have also included tests for the transactions which will help us in correcting any error which comes into the code without having to run any programs again and again.
73+
74+
- **Day 6 (15/11/2020)**: Today I have installed another application which will bring us POST requests necessary for carrying out transactions, for that we have refactored some code which has helped in running the application smoothly (serialised public key and signature), I have imported a few encoding and decoding functions which will help convert byte strings to required format (either lists, tuples, dictionaries, strings, or booleans). We have also been able to get the signature values in the form of a tuple using elliptic key Cryptography decoding and encoding functions. The application we are using is POSTMAN (i guess which will not be required in later stages).
75+
76+
- Next I have created a transaction pool which will store the transaction data which will be available for the node to read. Later I am also trying to broadcast transactions by deserialising them back to it's instance which will help read the transaction data and it's output. Later this design will also help in implementation of the frontend mechanics.
77+
78+
- **Day 7(16/11/2020)**: Today our goal was to complete the backend part of our project. This involved linking our cryptocurrency system to our blockchain system. We already have built our blockchain module in it's entirity by taking the data as some test string. This test string is now replaced with the actual transaction data which we require during any transaction activity. We have jsonified this data hence this can be readable accross any websites. We have also performed some test app scripts which will send data in realtime to check whether the application works properly or not. During this process we also encountered that there are multiple outputs adding into the same recepient, we dealt with this by deleting the output from the list which has the same address. I guess we cannot send the same amount transactions to the same recipient, but I am sure we will be able to tackle that as well.
79+
80+
*This will also be updated on a later basis*
81+
___
82+
## ACKNOWLEDGEMENTS
83+
84+
This project wouldn't have been possible without the help of certain people who although unknowingly helped me to understand concepts of Blockchain and Cryptocurrency systems. The course link which I took is given below.
85+
86+
[Udemy course on Cryptocurrency systems](https://www.udemy.com/share/102sB6AEAec15UQ3wJ/)

‎__pycache__/block.cpython-38.pyc

Copy file name to clipboard
1.92 KB
Binary file not shown.
1.3 KB
Binary file not shown.

‎backend/__init__.py

Copy file name to clipboardExpand all lines: backend/__init__.py
Whitespace-only changes.
166 Bytes
Binary file not shown.
699 Bytes
Binary file not shown.
3.14 KB
Binary file not shown.

‎backend/app/__init__.py

Copy file name to clipboard
+86Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import os
2+
import requests #Sends GET and POST requests in the application
3+
import random
4+
5+
from flask import Flask , jsonify, request #This imports the Flask and jsonify class from the flask module.
6+
7+
from backend.blockchain.blockchain import Blockchain #Required to GET the blockchain data.
8+
from backend.wallet.wallet import Wallet
9+
from backend.wallet.transactions import Transactions
10+
from backend.wallet.transaction_pool import TransactionPool
11+
from backend.pubsub import PubSub
12+
13+
app = Flask(__name__) #Flask class takes one parameter which is name.
14+
#This creates a class for endpoints. e.g. www.google.com/drive/
15+
#Here /drive is an endpoint to access google drive.
16+
blockchain = Blockchain()
17+
wallet = Wallet(blockchain)
18+
transaction_pool = TransactionPool()
19+
pubsub = PubSub(blockchain,transaction_pool)
20+
21+
#for i in range(3):
22+
#blockchain.addBlock(i)
23+
24+
@app.route('/') #This will output the default page of the website.
25+
def route_default():
26+
return 'Welcome to the blockchian'
27+
28+
@app.route('/blockchain')#This will output the blockchain as a class.
29+
def route_blockchain():
30+
return jsonify(blockchain.to_json())
31+
32+
@app.route('/blockchain/mine')#This will output the method to mine data inside the blockchain class.
33+
def route_blockchain_mine():
34+
transaction_data = transaction_pool.transaction_data()
35+
transaction_data.append(Transactions.reward_transaction(wallet).to_json())
36+
blockchain.addBlock(transaction_data)
37+
block = blockchain.chain[-1]
38+
pubsub.broadcast_block(block)
39+
transaction_pool.clear_blockchain_transactions(blockchain)
40+
41+
return jsonify(block.to_json())
42+
43+
@app.route('/wallet/transact',methods=['POST'])
44+
def route_wallet_transact():
45+
transaction_data = request.get_json()
46+
transaction = transaction_pool.existing_transaction(wallet.address)
47+
48+
if transaction:
49+
transaction.update(
50+
wallet,
51+
transaction_data['recepient'],
52+
transaction_data['amount']
53+
)
54+
else:
55+
transaction = Transactions(
56+
wallet,
57+
transaction_data['recepient'],
58+
transaction_data['amount']
59+
)
60+
61+
pubsub.broadcast_transaction(transaction)
62+
63+
return jsonify(transaction.to_json())
64+
65+
@app.route('/wallet/info')
66+
def route_wallet_info():
67+
return jsonify({'address':wallet.address, 'balance': wallet.balance })
68+
69+
70+
ROOT_PORT = 5000
71+
PORT = ROOT_PORT
72+
73+
if os.environ.get('PEER') == 'True':
74+
PORT = random.randint(5001,6000)
75+
result = requests.get(f"http://localhost:{ROOT_PORT}/blockchain")
76+
result_blockchain = Blockchain.from_json(result.json())
77+
try:
78+
blockchain.replace_chain(result_blockchain.chain)
79+
print("\n --Successfully synchronised the local chain")
80+
except Exception as e:
81+
print(f"\n--Error in synchronising: {e}")
82+
83+
84+
85+
86+
app.run(port=PORT)
Binary file not shown.

‎backend/blockchain/__init__.py

Copy file name to clipboardExpand all lines: backend/blockchain/__init__.py
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.

‎backend/blockchain/block.py

Copy file name to clipboard
+161Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import time
2+
from backend.util.crypto_hash import crypto_hash
3+
from backend.util.hex_to_bin import hex_to_bin
4+
from backend.config import MINE_RATE
5+
6+
GENESIS_DATA = {
7+
'number' : 0,
8+
'timestamp' : 1,
9+
'timerec' : '0',
10+
'last_hash' : 'genesis_last_hash',
11+
'hash' : 'genesis_hash',
12+
'data' : [],
13+
'difficulty': 3,
14+
'nonce':'genesis_nonce'
15+
}
16+
17+
class Block:
18+
"""
19+
Block is a fundamental part of the Blockchain. This is because it stores all the data present in a
20+
transaction or anything else related to storing of data.
21+
The block contains the following data.
22+
1. Number: The block number in the chain
23+
2. Timestamp: Recorded in nanoseconds.
24+
3. Time recorded: This is given so that it outputs the time in Days Months year and seconds format
25+
4. Hash: A unique hexadecimal number which defines the authencity of that block.
26+
5. Last hash: It is the hash value of the previous block.
27+
6. Data: The actual data inside the block.
28+
7. Difficulty: The number of leading zero's in the hash (binary value).
29+
8. Nonce: The number of iterations took to match the hash with the proper number of leading zeros.
30+
"""
31+
def __init__(self,number,timestamp,timerec,last_hash, hash, data, difficulty, nonce):
32+
self.number = number
33+
self.timestamp = timestamp
34+
self.timerec = timerec
35+
self.hash = hash
36+
self.last_hash = last_hash
37+
self.data = data
38+
self.difficulty= difficulty # Number of leading zeros in the block hash.
39+
self.nonce= nonce # Number of iterations required to reach the valid hash.
40+
41+
def __repr__(self): #This method is required to print out the class value of the block.
42+
return(
43+
f'Block-number: {self.number}\n'
44+
f'Block-time recorded: {self.timerec}\n' #Prints the date and time of the block entry.
45+
f'Block-timestamp: {self.timestamp}\n'
46+
f'Block-hash: {self.hash}\n'
47+
f'Block-last_hash: {self.last_hash}\n'
48+
f'Block-data: {self.data}\n'
49+
f'Difficulty: {self.difficulty}\n'
50+
f'Nonce: {self.nonce}\n\n'
51+
)
52+
53+
def __eq__(self,other): #It is another hidden class which will equate the
54+
#given instances in the form of a dictionary.
55+
return self.__dict__ == other.__dict__
56+
57+
def to_json(self):
58+
"""
59+
This serializes the block into it's dictionary representation. This is readable in JSON.
60+
"""
61+
return self.__dict__
62+
63+
@staticmethod
64+
def mine_block(last_block, data):
65+
"""
66+
Mining is a process which is used to add block into the chain through use of computational
67+
power. This process can become expensive as well as this can become easy to implement.
68+
We will keep on producing more data until we reach the leading 0's requirement for proof of work
69+
"""
70+
number = last_block.number + 1
71+
timestamp = time.time_ns() # Returns time in nanoseconds .
72+
last_hash = last_block.hash
73+
difficulty = Block.adjust_diff(last_block,timestamp)
74+
nonce = 0
75+
hash = crypto_hash(timestamp, last_hash, data, difficulty, nonce)
76+
77+
while hex_to_bin(hash)[0:difficulty] != '0' * difficulty: # We need to add leading zeroes according to difficulty
78+
#This process converts the code into binary format of hexadecimal hash value and then enters the loop
79+
nonce += 1 #Nonce value is incremented to one everytime this loop is executed
80+
timestamp = time.time_ns() #This is necessary.
81+
difficulty = Block.adjust_diff(last_block,timestamp) #Difficulty will get itself adjusted according to current block timestamp.
82+
hash = crypto_hash(timestamp, last_hash, data, difficulty, nonce)
83+
84+
timerec = time.asctime() # Returns time in form of string.
85+
86+
return Block(number,timestamp,timerec,last_hash, hash, data, difficulty, nonce)
87+
88+
@staticmethod
89+
def genesis():
90+
"""
91+
Generates the genesis block. Genesis block is the first block in the blockchain.
92+
"""
93+
return Block(**GENESIS_DATA) #Double asterisks are used to unpack the data
94+
#present in the GENESIS_DATA dictionary. This is one convenient method.
95+
96+
@staticmethod
97+
def from_json(block_json):
98+
"""
99+
To deserialize a block from it's JSON format back to a block instance
100+
"""
101+
return Block(**block_json)
102+
103+
@staticmethod
104+
def adjust_diff(last_block,new_timestamp):
105+
"""
106+
Calculate the difficulty with respect to MINE_RATE.
107+
If the difficulty is high we will decrement it by 1.(Slowly mined blocks)
108+
Else we will increment it by 1 (Quickly mined blocks)
109+
"""
110+
if(new_timestamp - last_block.timestamp) < MINE_RATE :
111+
return last_block.difficulty + 1
112+
if(last_block.difficulty-1)>0:
113+
return last_block.difficulty - 1
114+
115+
return 1
116+
117+
@staticmethod
118+
def isblockvalid(last_block,block):
119+
"""
120+
Validates the block using the following conditions
121+
1. Is block.last_hash == last_block.hash
122+
2. The block must meet the proof of work requirement.
123+
3. The difficulty must only be changed by 1.
124+
4. The block hash must be a valid combination of all the required fields.
125+
"""
126+
127+
if block.last_hash != last_block.hash:
128+
raise Exception("The block hash is invalid")
129+
130+
if hex_to_bin(block.hash)[0:block.difficulty] != '0'*block.difficulty :
131+
raise Exception('The PoW requirement was not met')
132+
133+
if abs(last_block.difficulty - block.difficulty) > 1:
134+
raise Exception('The difficulty level must only adjusted by one')
135+
136+
reconst_hash = crypto_hash(
137+
block.timestamp,
138+
block.last_hash,
139+
block.data,
140+
block.difficulty,
141+
block.nonce
142+
)
143+
144+
if block.hash != reconst_hash:
145+
raise Exception('The block hash must be correct')
146+
147+
148+
149+
def main():
150+
gen_block = Block.genesis()
151+
good_block = Block.mine_block(gen_block,'Hello')
152+
#bad_block.last_hash = 'Fished the hash'
153+
try:
154+
Block.isblockvalid(gen_block,good_block)
155+
156+
except Exception as e:
157+
print(f'isblockvalid:{e}')
158+
159+
160+
if __name__ == '__main__':
161+
main()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.