def __init__(self, transactions, previous_hash): self.transactions = transactions self.previous_hash = previous_hash self.timestamp = str(time()) proof = Proof(self) proof.run() self.hash = proof.hash self.nounce = proof.nounce self.tip = "true"
class Node: def __init__(self): self.keys = utils.generate_ec_key_pairs() self.pub_key_hash = utils.hash160(self.keys['public']) # self.address = utils.Base58.base58encode(hash160) self.waiting_txn_pool = [] self.lock = Lock() self.messages = deque() self.database_UTXO = UTXOTrie() self.blockchain = Blockchain(self.database_UTXO, self) self.recieved_txn_ids = [] self.proof = None self.run_now = True def __str__(self): return self.blockchain.__str__() def print(self, pad=""): print(pad, "##########---------- Node ----------##########") print(pad, "[@] Private Key : {}".format(self.keys['private'])) print(pad, "[@] Public Key : {}".format(self.keys['public'])) print(pad, "[@] Pub Key Hash : {}".format(self.pub_key_hash)) print(pad, "[@] Blockchain") self.blockchain.print(pad + " ") def start_mining(self): while self.run_now: if not self.waiting_txn_pool: # print("T: {} [slept]".format(current_thread().name)) time.sleep(5) # print("T: {} [woke]".format(current_thread().name)) self.check_messages() continue new_txn_pool = self.waiting_txn_pool.copy() self.waiting_txn_pool = [] coinbase_txn = transaction.TXN.create_coinbase_txn(self.keys) self.current_block = block.Block([coinbase_txn] + [txn for txn in new_txn_pool], self.blockchain.prev_block_hash) self.calculate_proof() def coin_recieved_txnid(self, txndata): self.recieved_txn_ids.append(txndata) def create_txn(self, reciever_address, amount): out_txns = [] out_txns.append(output_txn.OutputTXN(amount, reciever_address)) inp_txnids, total_amount = self.blockchain.get_inputs(amount) if (not inp_txnids) or (total_amount < amount): # not enough coin return False is_last_vout_self = False if total_amount > amount: is_last_vout_self = True out_txns.append( output_txn.OutputTXN(total_amount - amount, self.pub_key_hash)) inp_txns = [] for i in inp_txnids: script_sig = utils.create_script_sig(self.keys, i[0]) inp_txns.append(input_txn.InputTXN(i[0], i[1], script_sig)) new_txn = transaction.TXN(inp_txns, out_txns) with self.lock: self.messages.append(("txn", new_txn)) if is_last_vout_self: self.recieved_txn_ids.append( (new_txn.txnid, len(new_txn.out_txns) - 1)) with self.lock: network.Network.nodes[network.Network.address_map[ reciever_address]].coin_recieved_txnid((new_txn.txnid, 0)) with self.lock: for n in network.Network.nodes: if n != self: n.messages.append(("txn", new_txn)) return True @staticmethod def create_genesis_block(keys): coinbase_txn = transaction.TXN.create_coinbase_txn(keys) genesis_block = block.Block.create_genesis_block(coinbase_txn) genesis_block.prev_block_hash = "0" * 64 genesis_block.hash = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" return genesis_block def save_genesis_block(self, genesis_block): # we will always get it once at the start return self.blockchain.add_block(genesis_block, genesis=True) def send_txn_over_network(self, txn): network.distribute_txn(txn, self) def receive_txn(self, txn): ret = self.blockchain.verify_txn(txn) if not ret: print("T: {} TXN false".format(current_thread().name)) self.waiting_txn_pool.append(txn) def calculate_proof(self): self.proof = Proof(self.current_block) work = 0 while True: work = self.proof.run(work) if type(work) == int: self.check_messages() else: break if (work == None): return self.current_block.nonce = work.nonce self.current_block.hash = work.hash self.current_block.print() print("T: ", current_thread().name, "[MINED] [BLOCK]") self.blockchain.add_block(self.current_block) network.Network.distribute_block(self.current_block, self) def check_messages(self): while len(self.messages): with self.lock: msg_type, msg = self.messages.popleft() if msg_type == "txn": print("T: ", current_thread().name, "[RECEIVED] [TXN]") _txn = msg.create_copy() self.receive_txn(_txn) elif msg_type == "block": print("T: ", current_thread().name, "[RECEIVED] [BLOCK]") block = msg.create_copy() self.recieve_block(block) elif msg_type == "new_txn": print("T: ", current_thread().name, "[CREATED] [TXN]") reciever_address, amount = msg[0], msg[1] ret = self.create_txn(reciever_address, amount) def send_message(self, message): with self.lock: self.messages.append(message) def recieve_block(self, block): """ 1. block <- verify all txns / proof of work check check coinbase all props 2. current_block <- txns in block, next current block mem pool 3. start proof of works """ # block.print() output = self.blockchain.add_block(block) if not output: print("[?] Block not added") else: if self.proof != None: self.proof.quit = True