From d6394279bdafa531b43f73eab9a19ed2bd429b6b Mon Sep 17 00:00:00 2001 From: budthespud Date: Wed, 17 May 2023 23:35:30 -0300 Subject: [PATCH 1/5] Complicated the proof of work formula --- simpleCoin/miner.py | 17 ++++- simpleCoin/miner_config.py | 2 +- simpleCoin/test.py | 146 +++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 simpleCoin/test.py diff --git a/simpleCoin/miner.py b/simpleCoin/miner.py index a81f79a..2366cdc 100644 --- a/simpleCoin/miner.py +++ b/simpleCoin/miner.py @@ -66,13 +66,24 @@ def create_genesis_block(): def proof_of_work(last_proof, blockchain): + new_proof = 1 + check_proof = False + counter = 0 # Creates a variable that we will use to find our next proof of work incrementer = last_proof + 1 # Keep incrementing the incrementer until it's equal to a number divisible by 7919 # and the proof of work of the previous block in the chain start_time = time.time() - while not (incrementer % 7919 == 0 and incrementer % last_proof == 0): - incrementer += 1 + while check_proof is False: + hash_operation = hashlib.sha256( + str(new_proof ** 6 - last_proof ** 6).encode()).hexdigest() + #print(hash_operation) + if hash_operation[:6] == '000000': + check_proof = True + print('total hashes: ' + str(counter)) + else: + new_proof += 1 + counter += 1 # Check if any node found the solution every 60 seconds if int((time.time()-start_time) % 60) == 0: # If any other node got the proof, stop searching @@ -81,7 +92,7 @@ def proof_of_work(last_proof, blockchain): # (False: another node got proof first, new blockchain) return False, new_blockchain # Once that number is found, we can return it as a proof of our work - return incrementer, blockchain + return new_proof, blockchain def mine(a, blockchain, node_pending_transactions): diff --git a/simpleCoin/miner_config.py b/simpleCoin/miner_config.py index b259c1b..9773997 100644 --- a/simpleCoin/miner_config.py +++ b/simpleCoin/miner_config.py @@ -3,7 +3,7 @@ """ # Write your generated adress here. All coins mined will go to this address -MINER_ADDRESS = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi" +MINER_ADDRESS = "rqH1SmqNBqnNojCin9fI4BdFHN/KsazIj/xasjZK6i1iFi03AApkKtQXzm61lUA6TMCvfbKg7+ylLkYvKZMfMg==" # Write your node url or ip. If you are running it localhost use default MINER_NODE_URL = "http://localhost:5000" diff --git a/simpleCoin/test.py b/simpleCoin/test.py new file mode 100644 index 0000000..491fb31 --- /dev/null +++ b/simpleCoin/test.py @@ -0,0 +1,146 @@ +# Python Flask App to create Blockchain + +# For timestamp +import datetime + +# Calculating the hash +# in order to add digital +# fingerprints to the blocks +import hashlib + +# To store data +# in our blockchain +import json + +# Flask is for creating the web +# app and jsonify is for +# displaying the blockchain +from flask import Flask, jsonify + + +class Blockchain: + + # This function is created + # to create the very first + # block and set its hash to "0" + def __init__(self): + self.chain = [] + self.create_block(proof=1, previous_hash='0') + print(self.chain) + + # This function is created + # to add further blocks + # into the chain + def create_block(self, proof, previous_hash): + block = {'index': len(self.chain) + 1, + 'timestamp': str(datetime.datetime.now()), + 'proof': proof, + 'previous_hash': previous_hash} + self.chain.append(block) + return block + + # This function is created + # to display the previous block + def print_previous_block(self): + return self.chain[-1] + + # This is the function for proof of work + # and used to successfully mine the block + def proof_of_work(self, previous_proof): + new_proof = 1 + check_proof = False + + while check_proof is False: + hash_operation = hashlib.sha256( + str(new_proof ** 2 - previous_proof ** 2).encode()).hexdigest() + if hash_operation[:5] == '00000': + check_proof = True + else: + new_proof += 1 + + return new_proof + + def hash(self, block): + encoded_block = json.dumps(block, sort_keys=True).encode() + return hashlib.sha256(encoded_block).hexdigest() + + def chain_valid(self, chain): + previous_block = chain[0] + block_index = 1 + + while block_index < len(chain): + block = chain[block_index] + if block['previous_hash'] != self.hash(previous_block): + return False + + previous_proof = previous_block['proof'] + proof = block['proof'] + hash_operation = hashlib.sha256( + str(proof ** 2 - previous_proof ** 2).encode()).hexdigest() + + if hash_operation[:5] != '00000': + return False + previous_block = block + block_index += 1 + + return True + + +# Creating the Web +# App using flask +app = Flask(__name__) + +# Create the object +# of the class blockchain +blockchain = Blockchain() + + +# Mining a new block + + +@app.route('/mine_block', methods=['GET']) +def mine_block(): + print('mining') + previous_block = blockchain.print_previous_block() + previous_proof = previous_block['proof'] + proof = blockchain.proof_of_work(previous_proof) + previous_hash = blockchain.hash(previous_block) + block = blockchain.create_block(proof, previous_hash) + + response = {'message': 'A block is MINED', + 'index': block['index'], + 'timestamp': block['timestamp'], + 'proof': block['proof'], + 'previous_hash': block['previous_hash']} + + return jsonify(response), 200 + + +# Display blockchain in json format + + +@app.route('/get_chain', methods=['GET']) +def display_chain(): + response = {'chain': blockchain.chain, + 'length': len(blockchain.chain)} + return jsonify(response), 200 + + +# Check validity of blockchain + + +@app.route('/valid', methods=['GET']) +def valid(): + valid = blockchain.chain_valid(blockchain.chain) + + if valid: + response = {'message': 'The Blockchain is valid.'} + else: + response = {'message': 'The Blockchain is not valid.'} + return jsonify(response), 200 + + +# Run the flask server locally +app.run(host='127.0.0.1', port=5000) + +mine_block() \ No newline at end of file From 97050622b5362f0a497f46b9cdace574ebdd25a9 Mon Sep 17 00:00:00 2001 From: budthespud Date: Sun, 21 May 2023 22:36:14 -0300 Subject: [PATCH 2/5] Added node function to check balances & logic to reject transfers with insufficient funds. --- simpleCoin/miner.py | 54 ++++++++++++++++++++++++++++++++++---------- simpleCoin/wallet.py | 22 ++++++++++++++++-- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/simpleCoin/miner.py b/simpleCoin/miner.py index 2366cdc..243d5a4 100644 --- a/simpleCoin/miner.py +++ b/simpleCoin/miner.py @@ -78,7 +78,7 @@ def proof_of_work(last_proof, blockchain): hash_operation = hashlib.sha256( str(new_proof ** 6 - last_proof ** 6).encode()).hexdigest() #print(hash_operation) - if hash_operation[:6] == '000000': + if hash_operation[:5] == '00000': check_proof = True print('total hashes: ' + str(counter)) else: @@ -214,6 +214,30 @@ def get_blocks(): return chain_to_send +@node.route('/balance', methods=['GET']) +def get_balance(): + address = request.args.get("address") + global BLOCKCHAIN + chain_to_send = BLOCKCHAIN + transaction_history = [] + c_counter = 0 + d_counter = 0 + for block in chain_to_send: + y = block.data + transaction_history.append(y["transactions"]) + for x in transaction_history: + if x is not None: + for y in x: + # print(y['to']) + if y['to'] == address: + c_counter = c_counter + y['amount'] + if y['from'] == address: + d_counter = d_counter + int(y['amount']) + + balance = c_counter - d_counter + return str(balance) + + @node.route('/txion', methods=['GET', 'POST']) def transaction(): """Each transaction sent to this node gets validated and submitted. @@ -223,19 +247,25 @@ def transaction(): if request.method == 'POST': # On each new POST request, we extract the transaction data new_txion = request.get_json() + balance = requests.get(url=MINER_NODE_URL + '/balance', params={'address': new_txion['from']}) + parsed = json.loads(balance.text) + int_balance = int(json.dumps(parsed)) # Then we add the transaction to our list - if validate_signature(new_txion['from'], new_txion['signature'], new_txion['message']): - NODE_PENDING_TRANSACTIONS.append(new_txion) - # Because the transaction was successfully - # submitted, we log it to our console - print("New transaction") - print("FROM: {0}".format(new_txion['from'])) - print("TO: {0}".format(new_txion['to'])) - print("AMOUNT: {0}\n".format(new_txion['amount'])) - # Then we let the client know it worked out - return "Transaction submission successful\n" + if int_balance >= int(new_txion['amount']): + if validate_signature(new_txion['from'], new_txion['signature'], new_txion['message']): + NODE_PENDING_TRANSACTIONS.append(new_txion) + # Because the transaction was successfully + # submitted, we log it to our console + print("New transaction") + print("FROM: {0}".format(new_txion['from'])) + print("TO: {0}".format(new_txion['to'])) + print("AMOUNT: {0}\n".format(new_txion['amount'])) + # Then we let the client know it worked out + return "Transaction submission successful\n" + else: + return "Transaction submission failed. Wrong signature\n" else: - return "Transaction submission failed. Wrong signature\n" + return "Transaction submission failed. Insufficient Funds.\n" # Send pending transactions to the mining process elif request.method == 'GET' and request.args.get("update") == MINER_ADDRESS: pending = json.dumps(NODE_PENDING_TRANSACTIONS, sort_keys=True) diff --git a/simpleCoin/wallet.py b/simpleCoin/wallet.py index f2f74f9..7c641dc 100644 --- a/simpleCoin/wallet.py +++ b/simpleCoin/wallet.py @@ -27,12 +27,13 @@ def wallet(): response = None - while response not in ["1", "2", "3", "4"]: + while response not in ["1", "2", "3", "4", "5"]: response = input("""What do you want to do? 1. Generate new wallet 2. Send coins to another wallet 3. Check transactions - 4. Quit\n""") + 4. Check Balance + 5. Quit\n""") if response == "1": # Generate new wallet print("""=========================================\n @@ -55,6 +56,9 @@ def wallet(): elif response == "3": # Will always occur when response == 3. check_transactions() return wallet() # return to main menu + elif response == "4": # Will always occur when response == 4. + check_balance() + return wallet() # return to main menu else: quit() @@ -100,6 +104,20 @@ def check_transactions(): print('Connection error. Make sure that you have run miner.py in another terminal.') +def check_balance(): + """Retrieve the entire blockchain. With this you can check your + wallets balance. If the blockchain is to long, it may take some time to load. + """ + try: + res = requests.get('http://localhost:5000/balance', params = + {'address':"rqH1SmqNBqnNojCin9fI4BdFHN/KsazIj/xasjZK6i1iFi03AApkKtQXzm61lUA6TMCvfbKg7+ylLkYvKZMfMg=="}) + # print(str(res)) + parsed = json.loads(res.text) + print('balance: ' + (json.dumps(parsed, indent=4, sort_keys=True))) + except requests.ConnectionError: + print('Connection error. Make sure that you have run miner.py in another terminal.') + + def generate_ECDSA_keys(): """This function takes care of creating your private and public (your address) keys. It's very important you don't lose any of them or those wallets will be lost From 8d07a58c6e31aa7a96d997649cac6376936b3c83 Mon Sep 17 00:00:00 2001 From: budthespud Date: Tue, 23 May 2023 00:31:51 -0300 Subject: [PATCH 3/5] working changes --- simpleCoin/miner.py | 28 +++++++++++++++++----------- simpleCoin/miner_config.py | 4 ++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/simpleCoin/miner.py b/simpleCoin/miner.py index 243d5a4..929ef9d 100644 --- a/simpleCoin/miner.py +++ b/simpleCoin/miner.py @@ -103,6 +103,7 @@ def mine(a, blockchain, node_pending_transactions): In order to prevent too many coins to be created, the process is slowed down by a proof of work algorithm. """ + print('start of mining sequence') # Get the last proof of work last_block = BLOCKCHAIN[-1] last_proof = last_block.data['proof-of-work'] @@ -113,8 +114,10 @@ def mine(a, blockchain, node_pending_transactions): if not proof[0]: # Update blockchain and save it to file BLOCKCHAIN = proof[1] + print(proof) a.send(BLOCKCHAIN) - continue + proof[0] = True + miner_process.start() else: # Once we find a valid proof of work, we know we can mine a block so # ...we reward the miner by adding a transaction @@ -150,13 +153,16 @@ def mine(a, blockchain, node_pending_transactions): requests.get(url = MINER_NODE_URL + '/blocks', params = {'update':MINER_ADDRESS}) def find_new_chains(): + print('finding chains....') # Get the blockchains of every other node other_chains = [] for node_url in PEER_NODES: + # print('checking: ' + node_url) # Get their chains using a GET request block = requests.get(url = node_url + "/blocks").content # Convert the JSON object to a Python dictionary block = json.loads(block) + # print(len(block)) # Verify other node block is correct validated = validate_blockchain(block) if validated: @@ -168,20 +174,20 @@ def find_new_chains(): def consensus(blockchain): # Get the blocks from other nodes other_chains = find_new_chains() + # print(other_chains) # If our chain isn't longest, then we store the longest chain BLOCKCHAIN = blockchain - longest_chain = BLOCKCHAIN + my_chain = BLOCKCHAIN + longest_chain = {} for chain in other_chains: - if len(longest_chain) < len(chain): + if len(my_chain) < len(chain): longest_chain = chain - # If the longest chain wasn't ours, then we set our chain to the longest - if longest_chain == BLOCKCHAIN: - # Keep searching for proof - return False - else: - # Give up searching proof, update chain and start over again - BLOCKCHAIN = longest_chain - return BLOCKCHAIN + print('longer chain found') + else: + longest_chain = my_chain + + BLOCKCHAIN = longest_chain + return BLOCKCHAIN def validate_blockchain(block): diff --git a/simpleCoin/miner_config.py b/simpleCoin/miner_config.py index 9773997..20d2a8b 100644 --- a/simpleCoin/miner_config.py +++ b/simpleCoin/miner_config.py @@ -3,11 +3,11 @@ """ # Write your generated adress here. All coins mined will go to this address -MINER_ADDRESS = "rqH1SmqNBqnNojCin9fI4BdFHN/KsazIj/xasjZK6i1iFi03AApkKtQXzm61lUA6TMCvfbKg7+ylLkYvKZMfMg==" +MINER_ADDRESS = "e5yWZy7lcTm6ulr0rMmXxBGaYg4Mb10a+50SJb59MQm434y8bkRttCi5+SPWF4DxN3EIUEj2a2fLu9SVWRMe0g==" # Write your node url or ip. If you are running it localhost use default MINER_NODE_URL = "http://localhost:5000" # Store the url data of every other node in the network # so that we can communicate with them -PEER_NODES = [] +PEER_NODES = ['http://3.96.192.248:5000'] From baea0586580f9c1edd5917ebc5ff5f5a4e842ba5 Mon Sep 17 00:00:00 2001 From: budthespud Date: Tue, 23 May 2023 19:20:43 -0300 Subject: [PATCH 4/5] working changes --- simpleCoin/miner.py | 81 +++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/simpleCoin/miner.py b/simpleCoin/miner.py index 929ef9d..dab2a50 100644 --- a/simpleCoin/miner.py +++ b/simpleCoin/miner.py @@ -6,6 +6,7 @@ from flask import Flask, request from multiprocessing import Process, Pipe import ecdsa +import pprint from miner_config import MINER_ADDRESS, MINER_NODE_URL, PEER_NODES @@ -66,24 +67,13 @@ def create_genesis_block(): def proof_of_work(last_proof, blockchain): - new_proof = 1 - check_proof = False - counter = 0 # Creates a variable that we will use to find our next proof of work incrementer = last_proof + 1 # Keep incrementing the incrementer until it's equal to a number divisible by 7919 # and the proof of work of the previous block in the chain start_time = time.time() - while check_proof is False: - hash_operation = hashlib.sha256( - str(new_proof ** 6 - last_proof ** 6).encode()).hexdigest() - #print(hash_operation) - if hash_operation[:5] == '00000': - check_proof = True - print('total hashes: ' + str(counter)) - else: - new_proof += 1 - counter += 1 + while not (incrementer % 7919 == 0 and incrementer % last_proof == 0): + incrementer += 1 # Check if any node found the solution every 60 seconds if int((time.time()-start_time) % 60) == 0: # If any other node got the proof, stop searching @@ -92,7 +82,7 @@ def proof_of_work(last_proof, blockchain): # (False: another node got proof first, new blockchain) return False, new_blockchain # Once that number is found, we can return it as a proof of our work - return new_proof, blockchain + return incrementer, blockchain def mine(a, blockchain, node_pending_transactions): @@ -103,21 +93,21 @@ def mine(a, blockchain, node_pending_transactions): In order to prevent too many coins to be created, the process is slowed down by a proof of work algorithm. """ - print('start of mining sequence') # Get the last proof of work last_block = BLOCKCHAIN[-1] + print(last_block.data) last_proof = last_block.data['proof-of-work'] # Find the proof of work for the current block being mined # Note: The program will hang here until a new proof of work is found proof = proof_of_work(last_proof, BLOCKCHAIN) # If we didn't guess the proof, start mining again if not proof[0]: + print('not proof') # Update blockchain and save it to file BLOCKCHAIN = proof[1] - print(proof) + print(BLOCKCHAIN) a.send(BLOCKCHAIN) - proof[0] = True - miner_process.start() + continue else: # Once we find a valid proof of work, we know we can mine a block so # ...we reward the miner by adding a transaction @@ -153,16 +143,14 @@ def mine(a, blockchain, node_pending_transactions): requests.get(url = MINER_NODE_URL + '/blocks', params = {'update':MINER_ADDRESS}) def find_new_chains(): - print('finding chains....') # Get the blockchains of every other node other_chains = [] for node_url in PEER_NODES: - # print('checking: ' + node_url) # Get their chains using a GET request - block = requests.get(url = node_url + "/blocks").content + block = requests.get(url=node_url + "/blocks").content + print(block) # Convert the JSON object to a Python dictionary block = json.loads(block) - # print(len(block)) # Verify other node block is correct validated = validate_blockchain(block) if validated: @@ -174,20 +162,20 @@ def find_new_chains(): def consensus(blockchain): # Get the blocks from other nodes other_chains = find_new_chains() - # print(other_chains) # If our chain isn't longest, then we store the longest chain BLOCKCHAIN = blockchain - my_chain = BLOCKCHAIN - longest_chain = {} + longest_chain = BLOCKCHAIN for chain in other_chains: - if len(my_chain) < len(chain): + if len(longest_chain) < len(chain): longest_chain = chain - print('longer chain found') - else: - longest_chain = my_chain - - BLOCKCHAIN = longest_chain - return BLOCKCHAIN + # If the longest chain wasn't ours, then we set our chain to the longest + if longest_chain == BLOCKCHAIN: + # Keep searching for proof + return False + else: + # Give up searching proof, update chain and start over again + BLOCKCHAIN = longest_chain + return BLOCKCHAIN def validate_blockchain(block): @@ -253,25 +241,19 @@ def transaction(): if request.method == 'POST': # On each new POST request, we extract the transaction data new_txion = request.get_json() - balance = requests.get(url=MINER_NODE_URL + '/balance', params={'address': new_txion['from']}) - parsed = json.loads(balance.text) - int_balance = int(json.dumps(parsed)) # Then we add the transaction to our list - if int_balance >= int(new_txion['amount']): - if validate_signature(new_txion['from'], new_txion['signature'], new_txion['message']): - NODE_PENDING_TRANSACTIONS.append(new_txion) - # Because the transaction was successfully - # submitted, we log it to our console - print("New transaction") - print("FROM: {0}".format(new_txion['from'])) - print("TO: {0}".format(new_txion['to'])) - print("AMOUNT: {0}\n".format(new_txion['amount'])) - # Then we let the client know it worked out - return "Transaction submission successful\n" - else: - return "Transaction submission failed. Wrong signature\n" + if validate_signature(new_txion['from'], new_txion['signature'], new_txion['message']): + NODE_PENDING_TRANSACTIONS.append(new_txion) + # Because the transaction was successfully + # submitted, we log it to our console + print("New transaction") + print("FROM: {0}".format(new_txion['from'])) + print("TO: {0}".format(new_txion['to'])) + print("AMOUNT: {0}\n".format(new_txion['amount'])) + # Then we let the client know it worked out + return "Transaction submission successful\n" else: - return "Transaction submission failed. Insufficient Funds.\n" + return "Transaction submission failed. Wrong signature\n" # Send pending transactions to the mining process elif request.method == 'GET' and request.args.get("update") == MINER_ADDRESS: pending = json.dumps(NODE_PENDING_TRANSACTIONS, sort_keys=True) @@ -294,7 +276,6 @@ def validate_signature(public_key, signature, message): except: return False - def welcome_msg(): print(""" =========================================\n SIMPLE COIN v1.0.0 - BLOCKCHAIN SYSTEM\n From 5217cec785baa089313cf692e8f48cd8b1af5d9a Mon Sep 17 00:00:00 2001 From: budthespud Date: Tue, 23 May 2023 21:29:02 -0300 Subject: [PATCH 5/5] working changes --- simpleCoin/miner.py | 20 +++++++++++--------- simpleCoin/miner_config.py | 3 ++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/simpleCoin/miner.py b/simpleCoin/miner.py index dab2a50..31b9e1a 100644 --- a/simpleCoin/miner.py +++ b/simpleCoin/miner.py @@ -64,24 +64,29 @@ def create_genesis_block(): discarded and your transaction goes back as if it was never processed""" NODE_PENDING_TRANSACTIONS = [] - +start_time = time.time() def proof_of_work(last_proof, blockchain): # Creates a variable that we will use to find our next proof of work incrementer = last_proof + 1 # Keep incrementing the incrementer until it's equal to a number divisible by 7919 # and the proof of work of the previous block in the chain - start_time = time.time() + # start_time = time.time() + print(int((time.time()-start_time) % 60)) while not (incrementer % 7919 == 0 and incrementer % last_proof == 0): + # print('work') incrementer += 1 # Check if any node found the solution every 60 seconds if int((time.time()-start_time) % 60) == 0: + # print('check') + # If any other node got the proof, stop searching new_blockchain = consensus(blockchain) if new_blockchain: # (False: another node got proof first, new blockchain) return False, new_blockchain # Once that number is found, we can return it as a proof of our work + print(incrementer) return incrementer, blockchain @@ -95,17 +100,14 @@ def mine(a, blockchain, node_pending_transactions): """ # Get the last proof of work last_block = BLOCKCHAIN[-1] - print(last_block.data) last_proof = last_block.data['proof-of-work'] # Find the proof of work for the current block being mined # Note: The program will hang here until a new proof of work is found proof = proof_of_work(last_proof, BLOCKCHAIN) # If we didn't guess the proof, start mining again if not proof[0]: - print('not proof') # Update blockchain and save it to file BLOCKCHAIN = proof[1] - print(BLOCKCHAIN) a.send(BLOCKCHAIN) continue else: @@ -148,7 +150,7 @@ def find_new_chains(): for node_url in PEER_NODES: # Get their chains using a GET request block = requests.get(url=node_url + "/blocks").content - print(block) + # print(block) # Convert the JSON object to a Python dictionary block = json.loads(block) # Verify other node block is correct @@ -196,9 +198,9 @@ def get_blocks(): chain_to_send_json = [] for block in chain_to_send: block = { - "index": str(block.index), - "timestamp": str(block.timestamp), - "data": str(block.data), + "index": block.index, + "timestamp": block.timestamp, + "data": block.data, "hash": block.hash } chain_to_send_json.append(block) diff --git a/simpleCoin/miner_config.py b/simpleCoin/miner_config.py index 20d2a8b..b426f1f 100644 --- a/simpleCoin/miner_config.py +++ b/simpleCoin/miner_config.py @@ -10,4 +10,5 @@ # Store the url data of every other node in the network # so that we can communicate with them -PEER_NODES = ['http://3.96.192.248:5000'] +PEER_NODES = [] +# PEER_NODES = ['http://3.96.192.248:5000']