def create_new_block(self, transactions): with self.chain_lock: next_index = self.blockchain.next_index() last_hash = self.blockchain.last_hash() if [ tx for tx in transactions if tx in self.blockchain.all_transactions() ]: return block = Block(idx=next_index, transactions=transactions, previous_hash=last_hash) self.mining_thread = Mining(node=self, block=block) self.mining_thread.start() return
def run_trial(seed): np.random.seed(seed) bail_fund = 0 raised = 0 released = 0 mining = Mining() population = [] awaiting_trial = [] sample = generate_bail_sample() for day in range(N_DAYS): # monthly if day % 30 == 0: mined = mining.mine() bail_fund += mined raised += mined mining.update_miners() mining.update_price() population.extend( np.random.choice(sample, size=SIZE_PER_DAY, replace=False)) _population = [] for case in population: case.duration -= 1 if case.duration > 0: _population.append(case)
def stop(self): Mining.flagdown() print('Stop Mining.\n')
__author__ = "Abhishek Oza" __version__ = "1.0.0" from mining import Mining from cryptocurrency import Transactions from flask import Flask, jsonify, request, render_template import constants import init # creating web instance objInit = init.CreateDB() objMine = Mining() objTrnx = Transactions() app = Flask(__name__) # home page @app.route('/', methods=['GET']) def homepage(): response = { 1: 'Welcome to Blockchain Demo', 2: 'Please find below links...', 3: 'Send money -> localhost:5000/send', 4: 'Mine a block -> localhost:5000/mine', 5: 'Fetch all blocks -> localhost:5000/chain', 6: 'Check if chain is valid -> localhost:5000/checkchain' } return jsonify(response), 200 # send money
class Node: def __init__(self, ip, port, is_bootstrap, max_nodes, NBC, capacity, difficulty, bootstrap_ip, bootstrap_port, transactions): self.ip = ip self.port = port self.bootstrap = is_bootstrap self.max_nodes = max_nodes self.NBC = NBC self.capacity = capacity self.difficulty = difficulty self.bootstrap_ip = bootstrap_ip self.bootstrap_port = bootstrap_port self.transactions = transactions self.ring = {} self.wallet = Wallet() self.tx_pool = [] self.node_dict = { 'ip': self.ip, 'port': self.port, 'address': self.wallet.address, 'ready': False } self.mining_thread = None self.utxo_lock = Lock() self.tx_pool_lock = Lock() self.chain_lock = Lock() self.resolve_lock = Lock() if self.bootstrap: self.i_am_bootstrap() else: t = Thread(target=self.inform_bootstrap) t.start() def i_am_bootstrap(self): self.id = 0 self.node_dict['utxos'] = OrderedDict() self.ring = OrderedDict({self.id: self.node_dict}) self.blockchain = Blockchain([self.genesis_block()]) def genesis_block(self): amount = self.NBC * self.max_nodes transactions = [ Transaction(sender_address='0', sender_private_key=None, receiver_address=self.wallet.address, amount=amount, ring=self.ring).to_dict() ] return Block(idx=0, transactions=transactions, previous_hash='1', nonce='0') def inform_bootstrap(self): url = 'http://' + self.bootstrap_ip + ':' + self.bootstrap_port + '/hello_bootstrap' while True: try: response = r.post(url, data={'node': json.dumps(self.node_dict)}) code = response.status_code except r.exceptions.RequestException as e: print(e) code = 404 if code != 404: break else: sleep(3) if response.status_code != 200: print('Bootstrap says: "' + json.loads(response.json())['msg'] + '"') exit() else: response = json.loads(response.json()) self.id = response['id'] self.blockchain = Blockchain(response['blockchain']['block_list']) self.node_dict['utxos'] = OrderedDict(response['utxos']) print("I am in with id " + str(self.id)) valid, msg = self.blockchain.validate(self.difficulty) if not valid: print(msg) exit() while True: try: response = r.get('http://' + self.bootstrap_ip + ':' + self.bootstrap_port + '/broadcast_ring', params={'idx': self.id}) code = response.status_code except r.exceptions.RequestException as e: print(e) code = 401 sleep(3) if code == 200: break if self.transactions: self.start_transactions() def node_already_exists(self, new_node): msg = None for node in self.ring.values(): if new_node['ip'] == node['ip'] and new_node['port'] == node[ 'port']: msg = "You are already in with another wallet" if new_node['address'] == node['address']: msg = "I already have your wallet's address" return msg def register_node_to_ring(self, node_dict): if not self.bootstrap: return 400, "I am sorry, bootstrap is not here", None, None, None if self.max_nodes == len(self.ring): return 400, "Sorry we are full, " + str( self.max_nodes) + " nodes at a time", None, None, None msg = self.node_already_exists(node_dict) if msg: return 400, msg, None, None, None idx = len(self.ring) node_dict['utxos'] = OrderedDict() self.ring[idx] = node_dict success, error = self.create_transaction(node_dict['address'], self.NBC) if not success: return 400, error, None, None, None else: return 200, "OK", idx, self.blockchain.to_dict( ), self.ring[idx]['utxos'] def broadcast(self, data, endpoint): node_list = [ node for node_id, node in self.ring.items() if node_id != self.id and node['ready'] ] num_of_nodes = len(node_list) if num_of_nodes == 0: return True, [] url_list = [ 'http://' + node['ip'] + ':' + node['port'] + endpoint for node in node_list ] data_list = [data] * num_of_nodes p = Pool(num_of_nodes) try: successes, msg_list = list( zip(*p.starmap(send_stuff, zip(url_list, data_list)))) p.close() p.join() except r.exceptions.RequestException as e: print(e) p.close() p.join() exit() successful = sum(successes) == num_of_nodes return successful, list(msg_list) def broadcast_ring(self): while len([node for node in self.ring.values() if node['ready'] ]) != self.max_nodes - 1: print("Waiting for all nodes to get in") sleep(3) ring = self.ring.copy() ring[0]['ready'] = True success, msg_list = self.broadcast(data={'ring': json.dumps(ring)}, endpoint='/broadcast_ring') if not success: print("Failed broadcasting ring") exit() else: print("All nodes are informed, let\'s start") if self.transactions: t = Thread(target=self.start_transactions) t.start() self.ring[0]['ready'] = True def broadcast_transaction(self, tx_dict): success, msg_list = self.broadcast(data={'tx': json.dumps(tx_dict)}, endpoint='/validate_transaction') if success: msg = ("All nodes know about transaction now") else: msg = "Failed broadcasting transaction" for m in msg_list: print(m) return success, msg def broadcast_block(self, block_dict): success, msg_list = self.broadcast( data={'block': json.dumps(block_dict)}, endpoint='/validate_block') if success: msg = ("All nodes know about block " + str(block_dict['idx']) + " now") else: msg = "Failed broadcasting block" for m in msg_list: print(m) return success, msg def start_transactions(self): filename = os.path.join('transactions', str(self.max_nodes) + 'nodes', 'transactions' + str(self.id) + '.txt') with open(filename, 'r') as tx_file: txs = tx_file.readlines() start_time = time() successes = [] for tx in txs: recipient = self.ring[int(tx.split()[0].strip('id'))]['address'] amount = int(tx.split()[1]) success, msg = self.create_transaction(recipient, amount) print(msg) successes.append(success) sful = sum(successes) end_time = time() dirname = os.path.join('results', str(self.max_nodes) + 'nodes') Path(dirname).mkdir(parents=True, exist_ok=True) filename = os.path.join( dirname, 'tx_' + str(self.id) + '_' + str(self.capacity) + '_' + str(self.difficulty) + '.txt') with open(filename, 'w') as file: file.write( str(sful) + ' Transactions in ' + str(end_time - start_time) + ' seconds, ' + str(len(txs) - sful) + ' failed\n') def create_transaction(self, recipient, amount): try: self.utxo_lock.acquire() tx_dict = Transaction(sender_address=self.wallet.address, sender_private_key=self.wallet.private_key, receiver_address=recipient, amount=amount, ring=self.ring).to_dict() except ValueError as e: self.utxo_lock.release() return False, str(e) self.utxo_lock.release() s, m = self.broadcast_transaction(tx_dict) self.add_transaction_to_pool(tx_dict) return s, m def add_transaction_to_pool(self, tx_dict): with self.tx_pool_lock: if tx_dict not in self.tx_pool + self.blockchain.all_transactions( ): self.tx_pool.append(tx_dict) poolsize = len(self.tx_pool) transactions = self.tx_pool[:self.capacity] if poolsize >= self.capacity: if (not self.mining_thread or not self.mining_thread.is_alive()) and self.ring: self.create_new_block(transactions) def create_new_block(self, transactions): with self.chain_lock: next_index = self.blockchain.next_index() last_hash = self.blockchain.last_hash() if [ tx for tx in transactions if tx in self.blockchain.all_transactions() ]: return block = Block(idx=next_index, transactions=transactions, previous_hash=last_hash) self.mining_thread = Mining(node=self, block=block) self.mining_thread.start() return def validate_transaction(self, tx_dict): try: self.utxo_lock.acquire() tx = Transaction(sender_address=tx_dict['sender_address'], sender_private_key=None, receiver_address=tx_dict['receiver_address'], amount=tx_dict['amount'], ring=self.ring, signature=tx_dict['signature'], inputs=tx_dict['inputs'], outputs=tx_dict['outputs'], tx_id=tx_dict['transaction_id']) except ValueError as e: self.utxo_lock.release() return 400, str(e) self.utxo_lock.release() self.add_transaction_to_pool(tx_dict) return 200, "Transaction validated" def validate_block(self, block_dict): block = Block(idx=block_dict['idx'], transactions=block_dict['transactions'], previous_hash=block_dict['prev_hash'], nonce=block_dict['nonce'], hash_=block_dict['hash'], timestamp=block_dict['timestamp'], start_time=block_dict['start_time']) if not hasattr(self, 'blockchain'): return 200, "I just came here, what are you expecting me to say?" self.chain_lock.acquire() valid, msg = block.validate(self.difficulty, self.blockchain.last_hash()) if valid: # if self.ring: # with self.utxo_lock: # with self.tx_pool_lock: # if not self.resolve_tx(new_txs=block.transactions)[0]: # self.chain_lock.release() # return 400, "Block contains invalid transactions" with self.tx_pool_lock: self.tx_pool = [ tx for tx in self.tx_pool if not tx in block_dict['transactions'] ] if self.mining_thread and self.mining_thread.is_alive(): self.mining_thread.hash_found.set() self.blockchain.add_block(block) self.chain_lock.release() return 200, msg elif "Previous hash does not match" in msg: if block in self.blockchain.block_list: self.chain_lock.release() return 200, msg + ", but I already have this block" code, resolve_msg = self.resolve_conflicts() self.chain_lock.release() return code, msg + resolve_msg else: self.chain_lock.release() return 400, msg def resolve_conflicts(self): success, conflict_data = self.broadcast(data={}, endpoint='/resolve_conflict') if success: conflict_data.sort(key=lambda x: x[0], reverse=True) for length, hashchain, node_index in conflict_data: if length <= self.blockchain.length(): break idx = self.blockchain.index_of_fork(hashchain) try: response = r.get('http://' + self.ring[node_index]['ip'] + ':' + self.ring[node_index]['port'] + '/resolve_conflict', params={'idx': idx}) except r.exceptions.RequestException as e: continue rest_of_the_blockchain = json.loads( response.json())['blockchain'] blockchain = Blockchain(self.blockchain.block_list[:idx] + rest_of_the_blockchain, update_time=False) if blockchain.validate(self.difficulty)[0]: if self.mining_thread and self.mining_thread.is_alive(): self.mining_thread.hash_found.set() with self.resolve_lock: old_txs = self.blockchain.all_transactions(idx) new_txs = self.blockchain.all_transactions() self.blockchain = blockchain with self.utxo_lock: with self.tx_pool_lock: self.ring = self.resolve_tx(old_txs=old_txs, new_txs=new_txs, resolve=True)[1] return 200, ", node " + str( node_index) + " gave me the correct blockchain" return 200, ", but it was just a false alarm, I have the largest valid blockchain" else: return 400, ", I couldn't ask all nodes to resolve the conflict" def resolve_tx(self, old_txs=[], new_txs=[], resolve=False): self.tx_pool = [tx for tx in self.tx_pool if not tx in new_txs] old_txs = [tx for tx in old_txs if not tx in new_txs] # self.tx_pool = old_txs + self.tx_pool temp_ring = deepcopy(self.ring) for node_dict in temp_ring.values(): node_dict['utxos'] = OrderedDict() f = lambda tx: tx if isinstance(tx, dict) else tx.to_dict() transactions = [ f(tx) for block in self.blockchain.block_list for tx in block.transactions ] address_dict = {v['address']: int(k) for k, v in self.ring.items()} if resolve: transactions = transactions + self.tx_pool for tx in transactions: inputs = tx['inputs'] outputs = tx['outputs'] for out_id, tx_out in outputs.items(): receiver = temp_ring[address_dict[tx_out['recipient']]] receiver['utxos'][out_id] = tx_out if tx['signature'] == "genesis": continue sender = temp_ring[address_dict[tx['sender_address']]] for tx_in in inputs: if tx_in in sender['utxos']: del sender['utxos'][tx_in] else: return False, self.ring return True, temp_ring def write_block_times(self): avg, blocks = self.blockchain.block_time() dirname = os.path.join('results', str(self.max_nodes) + 'nodes') Path(dirname).mkdir(parents=True, exist_ok=True) filename = os.path.join( dirname, 'block_' + str(self.id) + '_' + str(self.capacity) + '_' + str(self.difficulty) + '.txt') with open(filename, 'w') as file: file.write('Average block time is ' + str(avg) + ' seconds, for ' + str(blocks) + 'blocks\n') def wallet_balance(self): with self.utxo_lock: balance = sum(utxo['amount'] for utxo in self.ring[self.id]['utxos'].values()) return balance def view_transactions(self): with self.chain_lock: last = self.blockchain.last_transactions() return last