def send_funds_from_to(self, sender_public_key_str: str, sender_private_key_str: str, recipient_public_key_str: str, value: float): if self.get_balance_for_public_key(sender_public_key_str) < value: print("Not enough balance, transaction discarded") return None if value <= 0: print("Value should be positive, transaction discarded") return None inputs = [] total = 0 for transaction_id, utxo in self.all_utxos.items(): if utxo.is_mine(sender_public_key_str): total += utxo.value inp = TransactionInput(transaction_id) inputs.append(inp) if total >= value + self.fee: break transaction = Transaction(sender_public_key_str, recipient_public_key_str, value, inputs) encoded = base64.b64decode(sender_private_key_str.encode('utf8')) sender_private_formated = PEM.encode(encoded, 'RSA PRIVATE KEY') transaction.generate_signature(import_key(sender_private_formated.encode('utf8'))) transaction.process_transaction(self.all_utxos, self.minimum_transaction, self.fee) return transaction
def generate(self): inputs = \ [ TransactionInput( src_hash=int_to_bytes( random.randint(0, sys.maxsize)), src_idx=random.randint( 0, constants.TRANSACTION_MAX_OUTPUTS), signature=int_to_bytes( random.randint(0, sys.maxsize)), key=self._ecdsa.public_key ) for _ in range(constants.TRANSACTION_MAX_INPUTS) ] outputs = \ [ TransactionOutput( amount=random.randint(0, 1000), key=int_to_bytes(random.randint(0, sys.maxsize)), ) for _ in range(constants.TRANSACTION_MAX_OUTPUTS) ] return Transaction(inputs=inputs, outputs=outputs)
def send_funds(self, all_utxos, recipient_public_key_str: str, value: float) -> Transaction: self.update_utxos(all_utxos) if self.get_balance(all_utxos) < value: raise Exception("Not enough balance, transaction discarded") if value <= 0: raise Exception("Value should be positive, transaction discarded") inputs = [] total = 0 for transaction_id, utxo in self.utxos.items(): total += utxo.value inp = TransactionInput(transaction_id) inputs.append(inp) if total >= value: break transaction = Transaction(self.public_key_str, recipient_public_key_str, value, inputs) transaction.generate_signature(self.private_key) for inp in inputs: del self.utxos[inp.transaction_output_id] return transaction
def generate(self): console.info("generating a transaction") tx, src_idx, amount_available = self.find_unspent() src_hash = tx.hash message = src_hash + int_to_bytes(src_idx) signature = self._ecdsa.sign(message) key = self._ecdsa.public_key tx_input = TransactionInput( src_hash=src_hash, src_idx=src_idx, signature=signature, key=key ) amount_send = int(amount_available * random.random()) fee = int((amount_available - amount_send) * random.random()) amount_rest = amount_available - amount_send - fee peers_with_address = self.peers_with_address() # If no known peers, we will send to ourselves receiver_key = self._ecdsa.public_key # Choose coin receiver at random try: receiver = random.choice(peers_with_address) receiver_key = receiver.address except IndexError: pass # Output that transfers `amount_send` coins to the chosen node output_send = TransactionOutput( amount=amount_send, key=receiver_key ) # Output that transfers the rest of the coins back to us. # The coins that are not in outputs constitute the transaction fee # (will be collected by the miner who will incude this transaction into # a new block) output_rest = TransactionOutput( amount=amount_rest, key=self._ecdsa.public_key ) return Transaction( inputs=[tx_input], outputs=[output_send, output_rest] )
def deserialize(cls, info: dict): sender = info['sender_public_key'] receiver = info['receiver_public_key'] value = info['value'] inputs = [] for input_data in info['input']: inputs.append(TransactionInput.deserialize(input_data)) outputs = [] for output_data in info['output']: outputs.append(TransactionOutput.deserialize(output_data)) transaction = Transaction(sender, receiver, value, inputs) transaction.transaction_id = info['id'] transaction.signature = info['signature'] transaction.outputs = outputs return transaction
def create_gift_coin(self, blockchain): """ This method creates a new coin for the new client """ # Get address of the client hash_public_key = self.hash_pubkey() coin_gift_tx_input = TransactionInput(prev_tx="1" * 64, pk_spender="1" * 64, signature=bytes( "\x11" * 64, encoding="utf-8")) coin_gift_tx_output = TransactionOutput( value=100, hash_pubkey_recipient=hash_public_key) coin_gift_tx = Transaction(tx_input=coin_gift_tx_input, tx_output=coin_gift_tx_output) transactions = [coin_gift_tx] nonce = 0 new_block = None while True: if len(blockchain.blocks) != 0: hash_prev_block = blockchain.blocks[len(blockchain.blocks) - 1].get_hash() new_block = Block(transactions, nonce, hash_prev_block) else: new_block = Block(transactions=transactions, nonce=nonce, prev_block_hash="0" * 64) if new_block.get_hash().startswith("0" * blockchain.difficulty): print("Nonce found:", nonce) break nonce += 1 print(coin_gift_tx.serialize()) message = "\x12" + new_block.serialize() self.socket.sendall(message.encode('utf-8'))
def send_message(self): while True: input_command = input() # This variable is set to True when is a server command send_message_to_server = True if input_command.startswith("cmd_new_tx"): # Show available transactions block_number = 0 print("==> List of available transactions:") print(self.blockchain.blocks) tx_unspent_counter = 0 for block in self.blockchain.blocks: transaction_number = 0 for transaction in block.transactions: if transaction.tx_output.hash_pubkey_recipient == self.hash_pubkey() and \ not transaction.is_already_spent(self.blockchain): tx_unspent_counter += 1 print("\t -- [ B:", block_number, " - T:", transaction_number, "]", "Value:", transaction.tx_output.value) transaction_number += 1 block_number += 1 if tx_unspent_counter > 0: block_number_spend = int(input("\tSelect block number: ")) transaction_number_spend = int( input("\tSelect transaction number: ")) transaction_spend = self.blockchain.blocks[ block_number_spend].transactions[ transaction_number_spend] address = input("\tAddress: ") value = int(input("\tValue: ")) signature_information = transaction_spend.get_hash() + \ transaction_spend.tx_output.hash_pubkey_recipient + \ address + \ str(value) route_private_key = "private_keys/" + str( self.socket.getsockname()[1]) + "_private_key.pem" hash_message = SHA256.new( signature_information.encode("utf-8")) private_key = ECC.import_key( open(route_private_key).read()) signer = DSS.new(private_key, "fips-186-3") signature = signer.sign(hash_message) new_tx_input = TransactionInput( prev_tx=transaction_spend.get_hash(), signature=signature, pk_spender=self.load_public_key()) new_tx_output = TransactionOutput( value=value, hash_pubkey_recipient=address) new_transaction = Transaction(tx_input=new_tx_input, tx_output=new_tx_output) print("\t-- Signing and sending transaction.") message = "\x10" + new_transaction.serialize() else: print("\t-- You do not have unspent transactions") send_message_to_server = False elif input_command.startswith("cmd_show_addresses"): # This is not a server command send_message_to_server = False base_path = "public_keys/" for file in os.listdir(base_path): pubkey_file = open(base_path + file) pubkey = pubkey_file.read() hash_object = RIPEMD160.new(data=pubkey.encode("utf-8")) print("\t>>", hash_object.hexdigest(), "[", file, "]") pubkey_file.close() elif input_command.startswith("cmd_gift"): send_message_to_server = False self.create_gift_coin(self.blockchain) else: message = input_command if send_message_to_server: self.socket.sendall(message.encode('utf-8'))