def form_transaction(sender, recipient, amount, utxo_obj, wif): outputs = [] inputs = [] spendable_utxo = utxo_obj.get_outputs_to_spend(sender, int(amount) + tx_fee) if len(spendable_utxo) == 0: raise Exception( "Address " + sender + " has not enough spendable outputs, can't form transaction") utxo_sum = 0 for v in spendable_utxo: utxo_sum += v.output.nVal outputs.append(Output(int(amount), recipient)) if utxo_sum - int(amount) - tx_fee > 0: outputs.append(Output(utxo_sum - int(amount) - tx_fee, sender)) inputs_outpoint_dict = {} # {spendable_output : input} for outs in spendable_utxo: inputs_outpoint_dict[outs] = Input(outs.txid, int(outs.vout, 16), "", 0xffffffff) # forming scriptSig for all inputs scripts = {} # {spendable_output : scriptSig} for spendable_output in inputs_outpoint_dict.keys(): scripts[spendable_output] = get_signed_scriptSig( spendable_output, inputs_outpoint_dict.copy(), outputs, wif) for k in scripts.keys(): inputs.append(Input(k.txid, int(k.vout, 16), scripts[k], 0xffffffff)) return Transaction(1, inputs, outputs, 0)
def add_new_block(self, miner_address): """ the function adds new block to the chain and rewards the miner :param miner_address: the miner address to reward """ number = len(self.chain) # handle genesis block if number == 0: prev = '0' * 32 else: prev = self.chain[-1].hash_code # transaction that rewards the miner # the input proof is arbitrary transaction_input = Input(str(len(self.chain)), -1, (miner_address, '')) transaction_output = Output(REWORD, miner_address) new_transaction = Transaction([transaction_input], [transaction_output]) self.add_transaction(new_transaction) # create the block block = Block.new_block(number, prev, self.transactions_pool) self.logger.info('Mining new block') block.mine_block() # set the block chain self.chain.append(block) self.transactions_pool = [] self.logger.info('The new block was added to the block chain')
def form_coinbase(miner_address, wif, g_miner_reward): outputs = [Output(g_miner_reward, miner_address)] inputs = [] scriptSig = script.get_scriptSig( wif, "tanya works better") # it can contain any data i like :) inputs.append(Input(coinbase_txid, 0xffffffff, scriptSig, 0xffffffff)) return CoinbaseTransaction(1, inputs, outputs, 0)
def do_send(self, args): if self.key_pair == 0: print("Haven`t key pair") return False split = args.strip().split(' ') if (not args or len(split) != 2): print("Please input [Recipient Address] [Amount]") return False t_recip, t_amount = split if t_recip == '-s': self.transactions.append(t_amount) return False t_amount = int(t_amount) try: # if True: self.update_unspend_pool() sum_of_inp, prev_outputs = self.get_outputs(t_amount) inputs = [Input(txid=bytearray.fromhex(txid), vout=vout) for txid, vout, o in prev_outputs] outputs = [Output(recipient=t_recip, value=t_amount)] if sum_of_inp - t_amount > FEE: change = sum_of_inp - t_amount - FEE outputs.append(Output(self.key_pair.get_address(), value=(change))) tx = Transaction(inputs, outputs) tx.sign_tx(prev_outputs, self.key_pair) s_tx = Serializer.serialize(tx) print(s_tx) self.transactions.append(s_tx) except Exception as identifier: print (f'Error:[{identifier}]') return False
def deserialize_input(self, serial): txid = little_endian(serial[:64]) serial = serial[64:] vout = int(little_endian(serial[:8]), 16) serial = serial[8:] slen, shift1 = get_script_length(serial) serial = serial[shift1:] scriptSig = serial[:slen] serial = serial[slen:] seq = int(little_endian(serial[:8]), 16) serial = serial[8:] shift = 80 + slen + shift1 return (shift, Input(txid, vout, scriptSig, seq))
def create_transaction(self, amount, recipient_address): """ the functions creates transaction which contains the amount of coins to send the recipient address, the function implements the transaction in the block chain :param amount: the amount to send :param recipient_address: the address to send the coins to :returns: true if there is enough money to the transaction and false otherwise """ # updates the balance self.update_balance() # checks weather there is enough money # to the transaction if amount > self.balance: self.logger.info(self.address + '- not enough money to send') return False # creates the new transaction new_transaction = Transaction([], []) sending_amount = 0 for unspent_output in self.unspent_outputs: # creating the proof data_to_sign = unspent_output.transaction_id data_to_sign += recipient_address data_to_sign = self.hash(data_to_sign).hexdigest() data_to_sign += str(amount) data_to_sign = self.hash(data_to_sign) signature = self.sign(data_to_sign) proof = (signature, self.public_key) new_transaction.add_input( Input(unspent_output.transaction_id, unspent_output.output_index, proof)) sending_amount += unspent_output.output.value if sending_amount >= amount: break new_transaction.add_output(Output(sending_amount, recipient_address)) # add change if it is needed if sending_amount > amount: change = sending_amount - amount new_transaction.add_output(Output(change, self.address)) # distributes the transaction self.logger.info(self.address + " is sending " + str(amount) + "LPC to " + recipient_address) self.distribute_transaction(new_transaction) return True
def deserialize_input(s): padd = 0 r_i = Input() r_i.txid = (bytearray.fromhex(s[0:64]))[::-1] #?txid padd += 64 s = s[64:] r_i.vout = int.from_bytes(bytearray.fromhex(s[0:8]), byteorder='little') #?vout padd += 8 s = s[8:] r_i.scriptsigsize, v_int = var_int.varint_to_int(s) #?sript sig size padd += v_int s = s[v_int:] r_i.scriptsig = s[0:r_i.scriptsigsize * 2] #? script sig padd += r_i.scriptsigsize * 2 s = s[r_i.scriptsigsize * 2:] r_i.sequence = bytearray.fromhex(s[0:8])[::-1] #? sequence padd += 8 return (r_i, padd)
def gui_handler(self, client_socket: socket.socket): self.send_verack_handler(client_socket) keep_open = True while keep_open: command_metadata = client_socket.recv(31) command = command_metadata[:12].decode('utf-8') if command == TX_COMMAND: payload = len(self.txs_handler.UTXO_pool).to_bytes(4, 'little') for input_inst in self.txs_handler.UTXO_pool.values(): payload += input_inst.serialize() client_socket.send(payload) tx = utils.receive_tx_data(client_socket) self.add_tx(tx) elif command == CREATE_BLOCK_COMMAND: # number_of_txs = len(self.outstanding_txs_pool).to_bytes(4, 'little') # client_socket.send(number_of_txs) # payload = b'' # for tx in self.outstanding_txs_pool: # tx_id, tx_value = tx.data['uniqueID'], tx.data['value'] # payload += tx_id.to_bytes(4, 'little') # payload += tx_value.to_bytes(4, 'little') # client_socket.send(payload) # command_metadata = client_socket.recv(31) # command = command_metadata[:12].decode('utf-8') # if command != BLOCK_COMMAND: # self.__update_events('Did not receive block command') # client_socket.close() # return # metadata_new_block = client_socket.recv(4) # number_of_txs_in_block = int.from_bytes(metadata_new_block, 'little') # txs = [] # for _ in range(number_of_txs_in_block): # tx_metadata = client_socket.recv(8) # tx_id = int.from_bytes(tx_metadata[:4], 'little') # tx_value = int.from_bytes(tx_metadata[4:], 'little') # txs.append((tx_id, tx_value)) # self.add_block(txs) self.generate_new_block() elif command == CREATE_CONNECTION: connection_metadata = client_socket.recv(19) connection = connection_metadata[:15].decode('utf-8').strip(), int.from_bytes(connection_metadata[15:], 'little') self.send_conexion_handler(connection) if connection in self.peers: self.send_getblocks_handler(connection) elif command == DEFAULT_DATA_COMMAND: addressA = load_pk('publickeyAlice.pem') addressB = load_pk('publickeyBob.pem') addressC = load_pk('publickeyCharlie.pem') scrooge = load_pk('publickeyScrooge.pem') transactions = [] # Create coin transaction inputs = [] outputs = [ Output(11, addressA), # Alice has 10 scrooge coins Output(10, addressB), # Alice has 10 scrooge coins ] unsigned = UnsignedTransaction(CREATECOINS_TYPE, inputs, outputs) to_sign = unsigned.DataForSigs() sigs = {} sigs[scrooge.export_key(format='DER')] = sign(to_sign, 'privatekeyScrooge.pem') transaction = Transaction(unsigned, sigs) self.add_tx(transaction) transactions.append(transaction) # Create block block = utils.create_block( transactions, self.blockchain.head_block_hash, ) time.sleep(1) self.add_block(block) continue transactions = [] # Pay coins transaction inputs = [ Input(transaction.txID, 10, addressA), Input(transaction.txID, 10, addressB), # Both spend their 10 scrooge coins ] outputs = [ Output(5, addressA), # Alice has 5 scrooge coins Output(15, addressB), # Bob has 15 scrooge coins ] unsigned = UnsignedTransaction(PAYCOINS_TYPE, inputs, outputs) to_sign = unsigned.DataForSigs() sigs = {} sigs[addressA.export_key(format='DER')] = sign(to_sign, 'privatekeyAlice.pem') sigs[addressB.export_key(format='DER')] = sign(to_sign, 'privatekeyBob.pem') transaction = Transaction(unsigned, sigs) self.add_tx(transaction) transactions.append(transaction) # Create block block = utils.create_block( transactions, self.blockchain.head_block_hash, ) self.add_block(block) elif command == GUICLOSE_COMMAND: keep_open = False client_socket.close()
def decode_input(payload): where_created = payload[:64].decode('utf-8') value = int.from_bytes(payload[64:68], 'little') owner = ECC.import_key(payload[68:]) return Input(where_created, value, owner)
def do_payout_for_block(self, block): # check if we already paid out already_used = self.already_used(block.get_coinbase()) if already_used: return existing = self.mongo.db.share_payout.find_one({'index': block.index}) if existing: pending = self.mongo.db.miner_transactions.find_one({'inputs.id': block.get_coinbase().transaction_signature}) if pending: return else: # rebroadcast transaction = Transaction.from_dict(self.config, self.mongo, existing['txn']) TU.save(self.config, self.mongo, transaction) self.broadcast_transaction(transaction) return try: shares = self.get_share_list_for_height(block.index) except: return total_reward = block.get_coinbase() if total_reward.outputs[0].to != self.config.address: return pool_take = 0.01 total_pool_take = total_reward.outputs[0].value * pool_take total_payout = total_reward.outputs[0].value - total_pool_take outputs = [] for address, x in shares.iteritems(): exists = self.mongo.db.share_payout.find_one({'index': block.index, 'txn.outputs.to': address}) if exists: raise PartialPayoutException('this index has been partially paid out.') payout = total_payout * x['payout_share'] outputs.append(Output(to=address, value=payout)) try: transaction = TransactionFactory( self.config, self.mongo, fee=0.0001, public_key=self.config.public_key, private_key=self.config.private_key, inputs=[Input(total_reward.transaction_signature)], outputs=outputs ) except NotEnoughMoneyException as e: print "not enough money yet" return except Exception as e: print e try: transaction.transaction.verify() except: raise print 'faucet transaction failed' TU.save(self.config, self.mongo, transaction.transaction) self.mongo.db.share_payout.insert({'index': block.index, 'txn': transaction.transaction.to_dict()}) self.broadcast_transaction(transaction.transaction)