diff --git a/.gitignore b/.gitignore index 7e99e36..8096062 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -*.pyc \ No newline at end of file +*.pyc +*scratch.py +xyf.txt +*user.py +*miner_config.py \ No newline at end of file diff --git a/README.md b/README.md index c34ede6..c61c163 100644 --- a/README.md +++ b/README.md @@ -1,68 +1 @@ -# SimpleCoin -Just a really simple, insecure and incomplete implementation of a blockchain for a cryptocurrency made in Python. The goal of this project is to make a working blockchain currency, keeping it as simple as possible and to be used as educational material. - ->This project is just being made for fun. If you want to make your own cryptocurrency you should probably take a look at the [Bitcoin Repository](https://github.com/bitcoin/bitcoin). - - -## What is a blockchain? - -Taking a look at the [Bitcoin organization wiki website](https://en.bitcoin.it/wiki/Main_Page) we can find this definition: - ->A block chain is a transaction database shared by all nodes participating in a system based on the Bitcoin protocol. A full copy of a currency's block chain contains every transaction ever executed in the currency. With this information, one can find out how much value belonged to each address at any point in history. - -You can find more information in the original [Bitcoin Paper](https://bitcoin.org/bitcoin.pdf). - -## How to run it - -First, install ```requirements.txt```. - -``` -pip install -r requirements.txt -``` - -Then you have 2 options: - -- Run ```miner.py``` to become a node and start mining -- Run ```wallet.py``` to become a user and send transactions (to send transactions you must run a node, in other words, you must run ```miner.py``` too) - -> Important: DO NOT run it in the python IDLE, run it in your console. The ```miner.py``` uses parallel processing that doesn't work in the python IDLE. - -## How this code work? - -There are 2 main scripts: - -- ```miner.py``` -- ```wallet.py``` - -### Miner.py - -This file is probably the most important. Running it will create a node (like a server). From here you can connect to the blockchain and process transactions (that other users send) by mining. As a reward for this work, you recieve some coins. The more nodes exist, the more secure the blockchain gets. - -```miner.py``` has 2 processes running in parallel: - -1. The first process takes care of mining, updating new blockchains and finding the proof of work. - -2. The second process runs the flask server where peer nodes and users can connect to ask for the entire blockchain or sumbmit new transactions. - -> Parallel processes don't run in python IDLE, so make sure you are running it from the console. - -![miner](https://k60.kn3.net/3/B/3/F/E/C/013.png) - -### Wallet.py - -This file is for those who don't want to be nodes but simple users. Running this file allows you to generate a new address, send coins and check your transaction history (keep in mind that if you are running this in a local server, you will need a "miner" to process your transaction). -When creating a wallet address, a new file will be generated with all your security credentials. You are supposed to keep it safe. - -![wallet](https://k60.kn3.net/6/F/E/3/8/2/887.png) - - -## Contribution - -Anybody is welcome to collaborate in this project. Feel free to push any pull request (even if you are new to coding). See ```CONTRIBUTING.md``` to learn how to contribute. - -Note: the idea of this project is to build a **really simple** blockchain system, so make sure all your code is easy to read (avoid too much code in 1 line) and don't introduce complex updates if they are not critical. In other words, keep it simple. - - -## Disclaimer - -By no means this project should be used for real purposes, it lacks security and may contain several bugs. +# SimpleCoin is fundamentally broken. HourCrypto is built on the same ideas, but works. look at that repo instead. diff --git a/requirements.txt b/requirements.txt index 16badde..89a4c04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Flask ecdsa requests +flask-sqlalchemy \ No newline at end of file diff --git a/simpleCoin/Block.py b/simpleCoin/Block.py new file mode 100644 index 0000000..1b37fea --- /dev/null +++ b/simpleCoin/Block.py @@ -0,0 +1,79 @@ +import hashlib +import ast +class Block(): + def __init__(self, index=-1, timestamp=-1, pow=-1, effort=-1,data=-1, previous_hash=-1): + """Returns a new Block object. Each block is "chained" to its previous + by calling its unique hash. + + Args: + index (int): Block number. + timestamp (int): Block creation timestamp. + data (dict): Data to be sent. + previous_hash(str): String representing previous block unique hash. + + Attrib: + index (int): Block number. + timestamp (int): Block creation timestamp. + data (dict): Data to be sent. + previous_hash(str): String representing previous block unique hash. + hash(str): Current block unique hash. + + """ + self.index = index + self.timestamp = timestamp + + self.proof_of_work = pow + self.effort = effort + self.data = data + ''' + data contains: + transactions: list + ''' + self.previous_hash = previous_hash + self.hash = self.hash_block() + + def hash_block(self): + """Creates the unique hash for the block. It uses sha256.""" + m = hashlib.sha256() + m.update((str(self.index) + str(self.timestamp) +str(self.proof_of_work)+ str(self.effort) + str(self.data) + str(self.previous_hash)).encode('utf-8')) + return m.hexdigest() + + def exportjson(self): + return { + "index": str(self.index), + "timestamp": str(self.timestamp), + "pow": str(self.proof_of_work), + "effort": str(self.effort), + "data": str(self.data), + "previous": str(self.previous_hash), + "hash": str(self.hash) + } + + def importjson(self,json): + self.index = int(json['index']) + self.timestamp = float(json['timestamp']) + self.proof_of_work = str(json['pow']) + self.effort = str(json['effort']) + self.data = ast.literal_eval(json['data']) + self.previous_hash = str(json['previous']) + self.hash = self.hash_block() + + def __repr__(self): + #def __init__(self, index, timestamp, pow, effort,data, previous_hash): + return "Block({},{},'{}','{}',{},'{}')".format(self.index,self.timestamp,self.proof_of_work,self.effort,self.data,self.previous_hash) + + def __str__(self): + return "i: {} time: {} \tpow: {} effort: {} data: {} \tprevious: {} hash: {}".format(self.index, self.timestamp,self.proof_of_work, self.effort, self.data, self.previous_hash, self.hash) + +def buildpow(index,timestamp,effort,data,previous_hash): + m = hashlib.sha256() + m.update((str(index) + str(timestamp) + str(effort) + str(data) + str(previous_hash)).encode('utf-8')) + return m +def validate(block): + if block.index == 0: + return True + pow = buildpow(block.index,block.timestamp,block.effort,block.data,block.previous_hash) + if block.proof_of_work == pow.hexdigest(): + return True + print("bad block",block.index) + return False \ No newline at end of file diff --git a/simpleCoin/miner.py b/simpleCoin/miner.py index 2e5b964..83eadc8 100644 --- a/simpleCoin/miner.py +++ b/simpleCoin/miner.py @@ -1,61 +1,58 @@ import time import hashlib +import sys import json import requests +import os +import secrets +import string import base64 from flask import Flask, request -from multiprocessing import Process, Pipe +from multiprocessing import Process, Queue import ecdsa - -from miner_config import MINER_ADDRESS, MINER_NODE_URL, PEER_NODES +import secrets +import string +import logging +import simpleCoin.user as user +from simpleCoin.Block import Block,buildpow,validate +from simpleCoin.miner_config import MINER_NODE_URL, PEER_NODES, PORT + +try: + assert user.public_key != "" and user.private_key != "" +except AssertionError: + print("You need to generate keys in your wallet") + sys.exit() + +log = logging.getLogger('werkzeug') +log.setLevel(logging.ERROR) node = Flask(__name__) +node.config['SECRET_KEY'] = user.secret_key - -class Block: - def __init__(self, index, timestamp, data, previous_hash): - """Returns a new Block object. Each block is "chained" to its previous - by calling its unique hash. - - Args: - index (int): Block number. - timestamp (int): Block creation timestamp. - data (str): Data to be sent. - previous_hash(str): String representing previous block unique hash. - - Attrib: - index (int): Block number. - timestamp (int): Block creation timestamp. - data (str): Data to be sent. - previous_hash(str): String representing previous block unique hash. - hash(str): Current block unique hash. - - """ - self.index = index - self.timestamp = timestamp - self.data = data - self.previous_hash = previous_hash - self.hash = self.hash_block() - - def hash_block(self): - """Creates the unique hash for the block. It uses sha256.""" - sha = hashlib.sha256() - sha.update((str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash)).encode('utf-8')) - return sha.hexdigest() +WORK = 20 +try: + assert WORK > 0 and WORK < 65 +except AssertionError: + print("Work value must be greater than 0 and less than 65") def create_genesis_block(): """To create each block, it needs the hash of the previous one. First block has no previous, so it must be created manually (with index zero and arbitrary previous hash)""" - return Block(0, time.time(), { - "proof-of-work": 9, + global WORK + work_ez = int(WORK / 4) + 1 + pow = "0" * work_ez + pad = "1337" + for i in range(4, 64): + pow += pad[i % len(pad)] + b = Block(0, time.time(), pow, "e", { "transactions": None}, - "0") + "0") + return b # Node's blockchain copy -BLOCKCHAIN = [create_genesis_block()] """ Stores the transactions that this node has in a list. If the node you sent the transaction adds a block @@ -63,29 +60,79 @@ def create_genesis_block(): discarded and your transaction goes back as if it was never processed""" NODE_PENDING_TRANSACTIONS = [] +BLOCKCHAIN = [] +ROOT = False +if len(PEER_NODES) == 0: + ROOT = True + BLOCKCHAIN.append(create_genesis_block()) - -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 9 - # and the proof of work of the previous block in the chain +def proof_of_work(a,last_block, data): start_time = time.time() - while not (incrementer % 7919 == 0 and incrementer % last_proof == 0): - incrementer += 1 + global ROOT + if ROOT: + new_block_index = last_block.index + 1 + new_block_timestamp = time.time() + + NODE_PENDING_TRANSACTIONS = [] + + + def random_str(): + # Generate a random size string from 3 - 27 characters long + rand_str = '' + for i in range(0, 1 + secrets.randbelow(25)): + rand_str += string.ascii_lowercase[secrets.randbelow(26)] # each char is a random downcase letter [a-z] + return rand_str + + def genhash(): + effort = random_str() + return effort, buildpow(new_block_index,new_block_timestamp,effort,data,last_block.hash) + + def leadingzeroes(digest): + n = 0 + result = ''.join(format(x, '08b') for x in bytearray(digest)) + for c in result: + if c == '0': + n += 1 + else: + break + return n + lead = 0 + if ROOT: + effort, pow_hash = genhash() + + global WORK + lead = leadingzeroes(pow_hash.digest()) + while lead < WORK: + if len(BLOCKCHAIN) == 0: + ROOT = False # Check if any node found the solution every 60 seconds - if int((time.time()-start_time) % 60) == 0: + if not ROOT or int((time.time() - start_time) % 60) == 0: + ROOT = True # If any other node got the proof, stop searching - new_blockchain = consensus(blockchain) + new_blockchain = consensus(a) 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 - return incrementer, blockchain + # generate new hash for next time + effort, pow_hash = genhash() + lead = leadingzeroes(pow_hash.digest()) + if not a.empty(): + qget = a.get() + + qfrom = qget[0] + new_block = qget[1] + print("received a block",qfrom) + if validate(new_block) and new_block.previous_hash == BLOCKCHAIN[len(BLOCKCHAIN) - 1].previous_hash: + BLOCKCHAIN.append(new_block) + return False, BLOCKCHAIN + + # Once that hash is found, we can return it as a proof of our work + mined_block = Block(new_block_index, new_block_timestamp, pow_hash.hexdigest(),effort, data, last_block.hash) + return True, mined_block def mine(a, blockchain, node_pending_transactions): - BLOCKCHAIN = blockchain + global BLOCKCHAIN + global WORK NODE_PENDING_TRANSACTIONS = node_pending_transactions while True: """Mining is the only way that new coins can be created. @@ -93,111 +140,202 @@ def mine(a, blockchain, node_pending_transactions): is slowed down by a proof of work algorithm. """ # Get the last proof of work - last_block = BLOCKCHAIN[len(BLOCKCHAIN) - 1] - 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]: - # Update blockchain and save it to file - BLOCKCHAIN = proof[1] - a.send(BLOCKCHAIN) - 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 - # First we load all pending transactions sent to the node server - NODE_PENDING_TRANSACTIONS = requests.get(MINER_NODE_URL + "/txion?update=" + MINER_ADDRESS).content + last_block = None + new_block_data = None + if ROOT: + last_block = BLOCKCHAIN[len(BLOCKCHAIN) - 1] + + NODE_PENDING_TRANSACTIONS = requests.get( + "http://" + MINER_NODE_URL + ":" + str(PORT) + "/txion?update=" + user.public_key).content NODE_PENDING_TRANSACTIONS = json.loads(NODE_PENDING_TRANSACTIONS) + # Then we add the mining reward NODE_PENDING_TRANSACTIONS.append({ "from": "network", - "to": MINER_ADDRESS, - "amount": 1}) - # Now we can gather the data needed to create the new block - new_block_data = { - "proof-of-work": proof[0], - "transactions": list(NODE_PENDING_TRANSACTIONS) - } - new_block_index = last_block.index + 1 - new_block_timestamp = time.time() - last_block_hash = last_block.hash - # Empty transaction list - NODE_PENDING_TRANSACTIONS = [] - # Now create the new block - mined_block = Block(new_block_index, new_block_timestamp, new_block_data, last_block_hash) + "to": user.public_key, + "amount": 1.0}) + + new_block_data = {"transactions": list(NODE_PENDING_TRANSACTIONS)} + proof = proof_of_work(a,last_block, new_block_data) + if not proof[0]: + BLOCKCHAIN = proof[1] + continue + else: + mined_block = proof[1] + + ''' + String + ''' + print("#",mined_block) + ''' + String + ''' + ''' + REPR + ''' + # print("b{} = ".format(mined_block.index), repr(mined_block)) + # if last_block.index == 1: + # print('work = {}'.format(work)) + # print("blockchain = [", end="") + # for i in range(0, len(BLOCKCHAIN)+1): + # print("b{}".format(i), end=",") + # print("]") + # sys.exit() + + ''' + END REPR + ''' + BLOCKCHAIN.append(mined_block) - # Let the client know this node mined a block - print(json.dumps({ - "index": new_block_index, - "timestamp": str(new_block_timestamp), - "data": new_block_data, - "hash": last_block_hash - }) + "\n") - a.send(BLOCKCHAIN) - requests.get(MINER_NODE_URL + "/blocks?update=" + MINER_ADDRESS) + a.put(["mined_lower",BLOCKCHAIN]) + requests.get("http://" + MINER_NODE_URL + ":" + str(PORT) + "/blocks?update=" + user.public_key) + + for node in PEER_NODES: + url = "http://" + node + ":" + str(PORT) + "/block" + headers = {"Content-Type": "application/json"} + data = mined_block.exportjson(); + requests.post(url,json = data, headers = headers) + def find_new_chains(): # Get the blockchains of every other node other_chains = [] for node_url in PEER_NODES: - # Get their chains using a GET request - block = requests.get(node_url + "/blocks").content + + blockchain_json = None + found_blockchain = [] + url = "http://"+node_url + ":" + str(PORT) + "/blocks" + blockchain_json = requests.get(url) + # Convert the JSON object to a Python dictionary - block = json.loads(block) - # Verify other node block is correct - validated = validate_blockchain(block) - if validated: - # Add it to our list - other_chains.append(block) + if blockchain_json is not None: + blockchain_json = json.loads(blockchain_json.content) + for block_json in blockchain_json: + temp = Block() + temp.importjson(block_json) + if validate(temp): + found_blockchain.append(temp) + # Verify other node block is correct + validated = validate_blockchain(found_blockchain) + if validated: + other_chains.append(found_blockchain) + continue return other_chains -def consensus(blockchain): + + + + +def validate_blockchain(blockchain): + global WORK + + previous = "" + for i in range(0,len(BLOCKCHAIN)-1): + block = BLOCKCHAIN[i] + if block.index == 0: + previous = block.hash + continue + else: + previous = BLOCKCHAIN[i-1].hash + if not validate(block): + return False + + transactions = block.data['transactions'] + + for transaction in transactions: + if transaction['from'] == "network" and transaction['amount'] != 1: + return False + if previous != block.previous_hash: + return False + return True + + +def validate_signature(public_key, signature, message): + """Verifies if the signature is correct. This is used to prove + it's you (and not someone else) trying to do a transaction with your + address. Called when a user tries to submit a new transaction. + """ + public_key = (base64.b64decode(public_key)).hex() + signature = base64.b64decode(signature) + vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key), curve=ecdsa.SECP256k1) + # Try changing into an if/else statement as except is too broad. + try: + return vk.verify(signature, message.encode()) + except: + return False + + +def consensus(a): + global ROOT + if len(PEER_NODES) == 0: + return False + global BLOCKCHAIN # Get the blocks from other nodes other_chains = find_new_chains() # If our chain isn't longest, then we store the longest chain - BLOCKCHAIN = blockchain - longest_chain = BLOCKCHAIN - for chain in other_chains: - if len(longest_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 + if len(other_chains) == 1: + BLOCKCHAIN = other_chains[0] + a.put(["consensus",BLOCKCHAIN]) + requests.get("http://" + MINER_NODE_URL + ":" + str(PORT) + "/blocks?update=" + user.public_key) + ROOT = True return BLOCKCHAIN + return BLOCKCHAIN + + +def welcome_msg(): + print(""" =========================================\n + SIMPLE COIN v1.0.0 - BLOCKCHAIN SYSTEM\n + =========================================\n\n + You can find more help at: https://github.com/cosme12/SimpleCoin\n + Make sure you are using the latest version or you may end in + a parallel chain.\n\n\n""") + + +@node.route('/block', methods=['post']) +def get_block(): + global BLOCKCHAIN + ip = request.remote_addr + new_block_json = request.get_json() + new_block = Block() + print("trying to receieve a block from",ip) + new_block.importjson(new_block_json) + validation = validate(new_block) + if validation and new_block.previous_hash == BLOCKCHAIN[len(BLOCKCHAIN)-1].previous_hash: + a.put(["get_block",new_block]) + if str(ip) != "127.0.0.1" and ip not in PEER_NODES: + print("added",ip) + PEER_NODES.append(str(ip)) + BLOCKCHAIN.append(new_block) + else: + print("val",validation, "nbph",new_block.previous_hash,"aph",BLOCKCHAIN[len(BLOCKCHAIN)-1].previous_hash) + return "500" + + + return "200" + -def validate_blockchain(block): - """Validate the submitted chain. If hashes are not correct, return false - block(str): json - """ - return True @node.route('/blocks', methods=['GET']) def get_blocks(): + global BLOCKCHAIN # Load current blockchain. Only you should update your blockchain - if request.args.get("update") == MINER_ADDRESS: - global BLOCKCHAIN - BLOCKCHAIN = b.recv() + if request.args.get("update") == user.public_key: + qget= a.get() + qfrom = qget[0] + BLOCKCHAIN = qget[1] + ip = request.remote_addr + if str(ip) != "127.0.0.1" and ip not in PEER_NODES: + print("added", ip) + PEER_NODES.append(str(ip)) chain_to_send = BLOCKCHAIN # Converts our blocks into dictionaries so we can send them as json objects later chain_to_send_json = [] for block in chain_to_send: - block = { - "index": str(block.index), - "timestamp": str(block.timestamp), - "data": str(block.data), - "hash": block.hash - } - chain_to_send_json.append(block) + chain_to_send_json.append(block.exportjson()) # Send our chain to whomever requested it chain_to_send = json.dumps(chain_to_send_json) @@ -206,10 +344,6 @@ def get_blocks(): @node.route('/txion', methods=['GET', 'POST']) def transaction(): - """Each transaction sent to this node gets validated and submitted. - Then it waits to be added to the blockchain. Transactions only move - coins, they don't create it. - """ if request.method == 'POST': # On each new POST request, we extract the transaction data new_txion = request.get_json() @@ -223,47 +357,65 @@ def transaction(): print("TO: {0}".format(new_txion['to'])) print("AMOUNT: {0}\n".format(new_txion['amount'])) # Then we let the client know it worked out + + # Push to all other available nodes + for node_url in PEER_NODES: + if node_url != request.remote_addr: + try: + headers = {"Content-Type": "application/json"} + requests.post(node_url + ":" + PORT + "/txion", json=new_txion, headers=headers) + except: + pass return "Transaction submission successful\n" else: 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: + elif request.method == 'GET' and request.args.get("update") == user.public_key: pending = json.dumps(NODE_PENDING_TRANSACTIONS) # Empty transaction list NODE_PENDING_TRANSACTIONS[:] = [] return pending -def validate_signature(public_key, signature, message): - """Verifies if the signature is correct. This is used to prove - it's you (and not someone else) trying to do a transaction with your - address. Called when a user tries to submit a new transaction. - """ - public_key = (base64.b64decode(public_key)).hex() - signature = base64.b64decode(signature) - vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(public_key), curve=ecdsa.SECP256k1) - # Try changing into an if/else statement as except is too broad. - try: - return vk.verify(signature, message.encode()) - except: - return False - +@node.route('/balances', methods=['GET']) +def get_balance(): + global BLOCKCHAIN + working = BLOCKCHAIN + balances = {} + balances_json = [] + + for block in working: + if block.data['transactions'] is not None: + for transaction in block.data['transactions']: + to = transaction['to'] + source = transaction['from'] + amount = transaction['amount'] + + if type(amount) == type("string"): + amount = eval(amount) + + if to in balances: + balances[to] += amount + else: + balances[to] = amount + if source != "network": + balances[source] -= amount + + for k, v in balances.items(): + account = { + "address": str(k), + "amount": str(v) + } + balances_json.append(account) -def welcome_msg(): - print(""" =========================================\n - SIMPLE COIN v1.0.0 - BLOCKCHAIN SYSTEM\n - =========================================\n\n - You can find more help at: https://github.com/cosme12/SimpleCoin\n - Make sure you are using the latest version or you may end in - a parallel chain.\n\n\n""") + return json.dumps(balances_json) if __name__ == '__main__': welcome_msg() - # Start mining - a, b = Pipe() + a = Queue() p1 = Process(target=mine, args=(a, BLOCKCHAIN, NODE_PENDING_TRANSACTIONS)) p1.start() # Start server to receive transactions - p2 = Process(target=node.run(), args=b) + p2 = Process(target=node.run(host="0.0.0.0", port=PORT), args=a) p2.start() diff --git a/simpleCoin/miner_config.py b/simpleCoin/miner_config.py index b259c1b..1ce0f9b 100644 --- a/simpleCoin/miner_config.py +++ b/simpleCoin/miner_config.py @@ -1,12 +1,8 @@ -"""Configure this file before you start mining. Check wallet.py for -more details. -""" - -# Write your generated adress here. All coins mined will go to this address -MINER_ADDRESS = "q3nf394hjg-random-miner-address-34nf3i4nflkn3oi" - +import simpleCoin.user +# Port to run on +PORT = 5000 # Write your node url or ip. If you are running it localhost use default -MINER_NODE_URL = "http://localhost:5000" +MINER_NODE_URL = "127.0.0.1" # Store the url data of every other node in the network # so that we can communicate with them diff --git a/simpleCoin/scratch.py b/simpleCoin/scratch.py new file mode 100644 index 0000000..d12ff2e --- /dev/null +++ b/simpleCoin/scratch.py @@ -0,0 +1,46 @@ +import hashlib +import secrets +import string +import time +from multiprocessing import Process, Queue +import os + +def random_str(): + # Generate a random size string from 3 - 27 characters long + rand_str = '' + for i in range(0, 1 + secrets.randbelow(25)): + rand_str += string.ascii_lowercase[secrets.randbelow(26)] # each char is a random downcase letter [a-z] + return rand_str + +def createhash(): + m = hashlib.sha256() + m.update(random_str().encode(('utf-8'))) + return m.hexdigest() + +def work(q): + test = createhash() + while test[0:4] != "0"*4 : + test = createhash() + print(test) + q.put(test) + +processes = [] +if __name__ == '__main__': + q = Queue() + for i in range(os.cpu_count()-3): + print('registering process %d' % i) + processes.append(Process(target=work,args = (q,)) ) + start = time.time() + print("start: ",start) + for process in processes: + process.start() + while True: + if not q.empty(): + test = q.get() + print(test) + for process in processes: + process.terminate() + + end = time.time() + print("end: ", end) + print("delta: ", end - start) \ No newline at end of file diff --git a/simpleCoin/user.py b/simpleCoin/user.py new file mode 100644 index 0000000..e61af5f --- /dev/null +++ b/simpleCoin/user.py @@ -0,0 +1,7 @@ +import hashlib +password = "Desktop boys" +m = hashlib.sha3_256() +m.update(password.encode('utf-8')) +secret_key = m.hexdigest() +private_key = "6e88f8181f002b07e1a7c7b0bc7cff176865670f381e45e305939903c49bdc90" +public_key = "xICxx0YyiVg0tf5nhWPUI/WUvX0/rs/jJXUI5vTxb87VJ1w9Va7xdbRWK37/hap/5HtAAAM6X312IUJpyyAM3A==" \ No newline at end of file diff --git a/simpleCoin/wallet.py b/simpleCoin/wallet.py index 8f3aec7..4dff728 100644 --- a/simpleCoin/wallet.py +++ b/simpleCoin/wallet.py @@ -46,6 +46,7 @@ def wallet(): print("Is everything correct?\n") print("From: {0}\nPrivate Key: {1}\nTo: {2}\nAmount: {3}\n".format(addr_from, private_key, addr_to, amount)) response = input("y/n\n") + print("From: {0}\nPrivate Key: {1}\nTo: {2}\nAmount: {3}\n".format(addr_from, private_key, addr_to, amount)) if response.lower() == "y": send_transaction(addr_from, private_key, addr_to, amount) else: # Will always occur when response == 3. @@ -103,6 +104,13 @@ def generate_ECDSA_keys(): public_key = vk.to_string().hex() #we are going to encode the public key to make it shorter public_key = base64.b64encode(bytes.fromhex(public_key)) + while "+" in public_key.decode() or "+" in private_key: + sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) # this is your sign (private key) + private_key = sk.to_string().hex() # convert your private key to hex + vk = sk.get_verifying_key() # this is your verification key (public key) + public_key = vk.to_string().hex() + # we are going to encode the public key to make it shorter + public_key = base64.b64encode(bytes.fromhex(public_key)) filename = input("Write the name of your new address: ") + ".txt" with open(filename, "w") as f: