def create_block(): with open(parentdir + "/core" + "/key.pem") as f: key = RSA.importKey(f.read()) """ First transaction for first block """ trans1 = { "vin": [None], # First transaction "vout": [{ "amount": 1000000.0, "address": key.publickey().exportKey().decode() }] } trans1["txid"] = sha(json.dumps(trans1)) block1 = { "header": { "prev_block_hash": None, "merkle_root": None, "timestamp": None, "nonce": None, "difficulty_target": "0" }, "transactions": [trans1] } utxo = UTXO() blockdb = Blockdb() blockdb.add_block(block1) utxo.add_trans(block1['transactions'], sha(json.dumps(block1['header'])))
def req_block(self, conn): """ conn : socket object the connection with the longest chain Send the hash of the latest block all nodes will send back the number of missing blocks, this node will extend using the longest chain method """ latest = self.blockdb.get_latest() conn.send("GET_BLOCKS".encode()) conn.send(str(latest).encode()) num_blocks = int(conn.recv(1024).decode()) block_num = 1 while block_num <= num_blocks: block_size = int(conn.recv(1024).decode()) block = conn.recv(1024) while len(block) < block_size: block += conn.recv(1024) block = json.loads(block.decode()) self.utxo.add_trans(block['transactions'], sha(json.dumps(block))) self.blockdb.add_block(block) ## DOESNT VARIFY THE BLOCK block_num += 1 print("Blockchain Updated")
def new_trans(self, amount, recepient): """ amount : float the total payment to the recepient recepient : str the public key address of the receiving party returns: json a json data structure with input/output information of the transaction """ trans, change = self._get_unspent(amount) vin = [] for t in trans: sig = self.sign(t[1]) # sign transaction id vin.append({ 'txid': t[1], # (id, txid, address, change, amount, block) 'change': t[3], # boolean 0 or 1 'sig': sig, }) vout = [{"amount": amount, "address": recepient}] if change > 0: vout.append({ "amount": change, "address": self.key.publickey().exportKey().decode() }) data = {"vin": vin, "vout": vout} data['txid'] = sha(json.dumps(data)) # hashes the transaction self.broadcast(data)
def add_block(self, block): block_hash = sha(json.dumps(block['header'])) # check if block is already saved get_block = self.get_block_by_hash(block_hash) if get_block != None: return None block_num = self.get_latest() if block_num == None: block_num = 1 else: block_num += 1 file = f"/block_{block_num}.json" # save the block as a file with open(parentdir + "/blocks" + file, "w") as f: json.dump(block, f) # add block to hash-table database with self.conn: self.c.execute("INSERT INTO blocks VALUES (NULL, :hash, :file)", { 'hash': block_hash, 'file': f'block_{block_num}.json' })
def verify_pow(self, header): diff = header["difficulty_target"] hashed = sha(json.dumps(header)) if hashed[:len(diff)] == diff: return True else: return False
def verify_prev_block(self, header): block_num = self.get_block_num() with open(self.path + f"/block_{block_num}.json") as f: block = json.load(f) hashed = sha(json.dumps(block['header'])) if hashed == header['prev_block_hash']: return True else: return False
def merkle_root(self, leaves): num_leaves = len(leaves) if num_leaves == 1: if type(leaves[0]) == dict: # For blocks with a single transaction return sha(json.dumps(leaves[0])) else: return leaves[0] parent = [ ] i = 0 while i < num_leaves: left = sha(json.dumps(leaves[i])) if (i + 1) < num_leaves: right = sha(json.dumps(leaves[i + 1])) else: right = sha(json.dumps(leaves[i])) parent.append(sha(left + right)) i += 2 return self.merkle_root(parent)
def proof_of_work(self, merkle_root): hashed = "1" * len(self.diff) while hashed[:len(self.diff)] != self.diff: header = { "prev_block_hash": self.prev_block_hash, "merkle_root": merkle_root, "timestamp": str(datetime.datetime.now().isoformat()), "nonce": str(random.getrandbits(32)), "difficulty_target": self.diff } hashed = sha(json.dumps(header)) return header
def new_block(self, conn, block): utxo = UTXO() blockdb = Blockdb() # check if block is already in the local chain exists = blockdb.get_block_by_hash(sha(block)) if exists != None: return None # ensure the block is valid if not self.verify("block", block): return None logging.debug("New block verified") # remove all transaction in the block from unconfirmed pool self.pool.check_new_block(sha(block)) # add all transaction outputs to utxo utxo.add_trans(block['transactions'], sha(json.dumps(block))) # remove all inputs from utxo utxo.remove_trans(block['transactions']) # save block in Blockdb blockdb.add_block(block) # propogate block self.client.prop_block(json.dumps(block).encode())
def verify_hash(self, trans): """ trans : dict transaction data structure returns : boolean True if txid matches the hash of the transaction """ tcopy = trans.copy() del tcopy['txid'] hashed = sha(json.dumps(tcopy)) if trans['txid'] == hashed: return True else: return False