def send_transaction(): log_ip(request, inspect.stack()[0][3]) data = request.json transaction = Transaction.from_json(data["transaction"]).object() sig = data["signature"] transaction.add_sign(sig) logger.debug(transaction) logger.info("Wallet: Attempting to Send Transaction") try: r = requests.post( "http://0.0.0.0:" + str(consts.MINER_SERVER_PORT) + "/newtransaction", data=compress(transaction.to_json()), timeout=(5, 1), ) if r.status_code == 400: response.status = 400 logger.error( "Wallet: Could not Send Transaction. Invalid transaction: " + r.text) return "Invalid Transaction: " + r.text except Exception as e: response.status = 400 logger.error("Wallet: Could not Send Transaction. Try Again." + str(e)) return "Internal error, try again" else: logger.info("Wallet: Transaction Sent, Wait for it to be Mined") return "Done"
def create_transaction(receiver_public_keys: List[str], amounts: List[int], sender_public_key, message="") -> Transaction: vout = {} vin = {} current_amount = 0 total_amount = sum(amounts) i = 0 for so, utxo_list in BLOCKCHAIN.active_chain.utxo.utxo.items(): tx_out = utxo_list[0] if current_amount >= total_amount: break if tx_out.address == sender_public_key: current_amount += tx_out.amount vin[i] = TxIn(payout=SingleOutput.from_json(so), pub_key=sender_public_key, sig="") i += 1 for i, address in enumerate(receiver_public_keys): vout[i] = TxOut(amount=amounts[i], address=address) change = (current_amount - total_amount) if change > 0: vout[i + 1] = TxOut(amount=change, address=sender_public_key) tx = Transaction(version=consts.MINER_VERSION, locktime=0, timestamp=int(time.time()), vin=vin, vout=vout, message=message) return tx
def process_new_transaction(request_data: bytes) -> str: global BLOCKCHAIN transaction_json = decompress(request_data) if transaction_json: try: tx = Transaction.from_json(transaction_json).object() # Add transaction to Mempool if tx not in BLOCKCHAIN.mempool: if BLOCKCHAIN.active_chain.is_transaction_valid(tx): logger.debug( "Valid Transaction received, Adding to Mempool") BLOCKCHAIN.mempool.add(tx) # Broadcast block to other peers send_to_all_peers("/newtransaction", request_data) else: return "Transaction Already received" else: logger.debug( "The transation is not valid, not added to Mempool") return "Not Valid Transaction" except Exception as e: logger.error("Server: New Transaction: Invalid tx received: " + str(e)) raise e return "Not Valid Transaction" return "Done"
def __mine(self, mempool: Set[Transaction], chain: Chain, payout_addr: str) -> Block: c_pool = list(copy.deepcopy(mempool)) mlist, fees = self.__calculate_best_transactions(c_pool) # logger.debug(f"Miner: Will mine {len(mlist)} transactions and get {fees} scoins in fees") coinbase_tx_in = { 0: TxIn(payout=None, sig="Receiving some Money", pub_key="Does it matter?") } coinbase_tx_out = { 0: TxOut(amount=chain.current_block_reward(), address=payout_addr), 1: TxOut(amount=fees, address=payout_addr), } coinbase_tx = Transaction( is_coinbase=True, version=consts.MINER_VERSION, fees=0, timestamp=int(time.time()), locktime=-1, vin=coinbase_tx_in, vout=coinbase_tx_out, ) mlist.insert(0, coinbase_tx) block_header = BlockHeader( version=consts.MINER_VERSION, height=chain.length, prev_block_hash=dhash(chain.header_list[-1]), merkle_root=merkle_hash(mlist), timestamp=int(time.time()), target_difficulty=chain.target_difficulty, nonce=0, ) DONE = False for n in range(2**64): block_header.nonce = n bhash = dhash(block_header) if chain.is_proper_difficulty(bhash): block = Block(header=block_header, transactions=mlist) requests.post("http://0.0.0.0:" + str(consts.MINER_SERVER_PORT) + "/newblock", data=compress(block.to_json())) logger.info( f"Miner: Mined Block with {len(mlist)} transactions, Got {fees} in fees and {chain.current_block_reward()} as reward" ) DONE = True break if not DONE: logger.error( "Miner: Exhausted all 2 ** 64 values without finding proper hash" )
def calculate_transaction_fees(tx: Transaction, w: Wallet, bounty: int, fees: int): current_amount = 0 i = 0 for so, utxo_list in BLOCKCHAIN.active_chain.utxo.utxo.items(): tx_out = utxo_list[0] if utxo_list[2]: # check for coinbase TxIn Maturity if not (BLOCKCHAIN.active_chain.length - utxo_list[1].height) >= consts.COINBASE_MATURITY: continue if current_amount >= bounty + fees: break if tx_out.address == w.public_key: current_amount += tx_out.amount tx.vin[i] = TxIn(payout=SingleOutput.from_json(so), pub_key=w.public_key, sig="") i += 1 tx.vout[1].amount = current_amount - bounty - fees tx.fees = fees tx.sign(w)
def send_bounty(bounty: int, receiver_public_key: str, fees: int): current_balance = check_balance() if current_balance < bounty + fees: print("Insuficient balance ") print("Current balance : " + str(current_balance)) print("You need " + str(current_balance - bounty) + "more money") else: transaction = Transaction( version=1, locktime=0, timestamp=2, is_coinbase=False, fees=0, vin={}, vout={ 0: TxOut(amount=bounty, address=receiver_public_key), 1: TxOut(amount=0, address=MY_WALLET.public_key) }, ) calculate_transaction_fees(transaction, MY_WALLET, bounty, fees) logger.debug(transaction) logger.info("Wallet: Attempting to Send Transaction") try: requests.post( "http://0.0.0.0:" + str(consts.MINER_SERVER_PORT) + "/newtransaction", data=compress(transaction.to_json()), timeout=(5, 1), ) except Exception as e: logger.error("Wallet: Could not Send Transaction. Try Again." + str(e)) else: logger.info("Wallet: Transaction Sent, Wait for it to be Mined")
def send_amount(self, receiver_address: str, amount: int, message: Optional[str]) -> bool: contract_private_key = int(self.current_contract_priv_key) contract_wallet = Wallet(pub_key=None, priv_key=contract_private_key) data = { 'bounty': amount, 'sender_public_key': contract_wallet.public_key, 'receiver_public_key': receiver_address, 'message': message } r = requests.post("http://0.0.0.0:" + str(consts.MINER_SERVER_PORT) + "/makeTransaction", json=data) tx_data = r.json() logger.debug(f"BlockchainVmInterface: send_amount - Make Transaction returned: {tx_data}") transaction = Transaction.from_json(tx_data['send_this']).object() signed_string = contract_wallet.sign(tx_data['sign_this']) transaction.add_sign(signed_string) return self.add_contract_tx_to_mempool(transaction)
def update_contract_output(self, output: str) -> bool: contract_private_key = int(self.current_contract_priv_key) contract_wallet = Wallet(pub_key=None, priv_key=contract_private_key) contract_address = contract_wallet.public_key cc, _, cp = get_cc_co_cp_by_contract_address(contract_address) if cp != str(contract_private_key): # We should panic logger.error(f"Contract private keys do not match for address {contract_address}") return False if cc == '': logger.error(f"Contract code is empty for address {contract_address}") return False cpub = contract_address data = { 'bounty': 1, 'sender_public_key': contract_wallet.public_key, 'receiver_public_key': 'AAAAA' + cpub[5:], # Some random address 'message': "Updated output of the tx", # Possibly add the prev tx_hash here 'contract_code': cc } r = requests.post("http://0.0.0.0:" + str(consts.MINER_SERVER_PORT) + "/makeTransaction", json=data) logger.debug(f"BlockchainVmInterface: update_contract_output - Make Transaction returned: {r.text}") res = r.json()['send_this'] tx_data = json.loads(res) tx_data['contract_output'] = output tx_data['contract_priv_key'] = cp tx_data['data'] = "" # Leaving it empty tx_data['timestamp'] = int(time.time()) for num in tx_data['vout']: tx_data['vout'][num]["address"] = cpub transaction = Transaction.from_json(json.dumps(tx_data)).object() tx_vin = transaction.vin transaction.vin = {} transaction.contract_output = None tx_json_to_sign = transaction.to_json() signed_string = contract_wallet.sign(tx_json_to_sign) transaction.vin = tx_vin transaction.contract_output = output transaction.add_sign(signed_string) return self.add_contract_tx_to_mempool(transaction)
def process_new_transaction(request_data: bytes) -> Tuple[bool, str]: global BLOCKCHAIN transaction_json = decompress(request_data) if transaction_json: try: tx = Transaction.from_json(transaction_json).object() # Validations for txIn in tx.vin.values(): if is_valid_contract_address(txIn.pub_key): return False, "Cannot send funds from a contract address" if tx.contract_output is not None: return False, "Contract Output should be None" if tx.contract_code != "": # This is a contract contract_address = tx.get_contract_address() # Ensure that there is no other contract on this contract address cc, _, _ = get_cc_co_cp_by_contract_address(contract_address) if cc != "": return False, "There is already some other contract at this contract address" # Add transaction to Mempool if tx not in BLOCKCHAIN.mempool: ok, msg = BLOCKCHAIN.active_chain.is_transaction_valid(tx) if ok: logger.debug( "Valid Transaction received, Adding to Mempool") BLOCKCHAIN.mempool.add(tx) logger.debug( f"Mempool now contains {len(BLOCKCHAIN.mempool)} transaction(s)" ) # Broadcast block to other peers send_to_all_peers("/newtransaction", request_data) else: logger.debug( "The transation is not valid, not added to Mempool - " + msg) return False, "Not Valid Transaction: " + msg else: return True, "Transaction Already received" except Exception as e: logger.error("Server: New Transaction: Invalid tx received: " + str(e)) return False, "Not Valid Transaction" return True, "Done"
def get_peer_url(peer: Dict[str, Any]) -> str: return "http://" + str(peer["ip"]) + ":" + str(peer["port"]) if __name__ == "__main__": # The singleOutput for first coinbase transaction in genesis block so = SingleOutput(txid=dhash(first_block_transaction[0]), vout=0) first_transaction = Transaction( version=1, locktime=0, timestamp=3, is_coinbase=False, fees=4000000000, vin={0: TxIn(payout=so, sig="", pub_key=consts.WALLET_PUBLIC)}, vout={0: TxOut(amount=1000000000, address=consts.WALLET_PUBLIC)} ) sign_copy_of_tx = copy.deepcopy(first_transaction) sign_copy_of_tx.vin = {} w = Wallet() w.public_key = consts.WALLET_PUBLIC w.private_key = consts.WALLET_PRIVATE sig = w.sign(sign_copy_of_tx.to_json()) first_transaction.vin[0].sig = sig peer_list = fetch_peer_list() print(peer_list)
for i in range(peer_height, ACTIVE_CHAIN.length): hash_list.append(dhash(ACTIVE_CHAIN.header_list[i])) logger.debug(peer_height) return jsonify(hash_list) # The singleOutput for first coinbase transaction in genesis block so = SingleOutput(txid=dhash(genesis_block_transaction[0]), vout=0) first_block_transactions = [ Transaction( version=1, locktime=0, timestamp=2, is_coinbase=True, fees=0, vin={0: TxIn(payout=None, sig="", pub_key=consts.WALLET_PUBLIC)}, vout={ 0: TxOut(amount=5000000000, address=consts.WALLET_PUBLIC), 1: TxOut(amount=4000000000, address=consts.WALLET_PUBLIC), }, ), Transaction( version=1, locktime=0, timestamp=3, is_coinbase=False, fees=4000000000, vin={0: TxIn(payout=so, sig="", pub_key=consts.WALLET_PUBLIC)}, vout={0: TxOut(amount=1000000000, address=consts.WALLET_PUBLIC)}, ), ]