def create_tx_outs(receiver_address, my_address, amount, left_over_amount): tx_out = TxOut(receiver_address, amount) if left_over_amount == 0: return [tx_out] else: left_over_tx = TxOut(my_address, left_over_amount) return [tx_out, left_over_tx]
def give(self, address, amt): if amt > self.balance(): print("Insufficient balance") return myOuts = [ txOut for txOut in self.chain.pool.txOuts if txOut.address.equals(self.pubKey) ] toGive = amt consumed = [] created = [TxOut(address, amt)] for out in myOuts: consumed.append(TxIn(out.txHash, out.idx)) if out.value >= toGive: created.append(TxOut(self.pubKey, out.value - toGive)) toGive -= out.value if toGive <= 0: break tx = Transaction(consumed, created) for i in range(len(consumed)): tx.sign(self.privKey, i) self.pendingTxs.append(tx) self.sendToPeers({"type": 'TRANSACTION', "data": tx.toJSON()})
def clone(self): newPool = UTXOPool() for txOut in self.txOuts: newTxOut = TxOut(txOut.address, txOut.value) newTxOut.txHash = txOut.txHash newTxOut.idx = txOut.idx newPool.txOuts.append(newTxOut) return newPool
def create_tx_outs(self, receiver_address, amount, left_over_amount): amount = Decimal(amount) tx_out_1 = TxOut(receiver_address, amount) tx_outs = [tx_out_1] if left_over_amount > 0: my_address = self.get_public_key() left_over_tx_out = TxOut(my_address, left_over_amount) tx_outs.append(left_over_tx_out) return tx_outs
def __init__(self): self.genesis_transaction = Transaction( [TxIn('', 0, '')], [TxOut(get_public_from_wallet(), 50)]) self._blockchain = [self.get_genesis_block()] self.difficulty_bits = 15 self.unspent_tx_outs = process_transactions([self.genesis_transaction], [], 0)
def build_transaction(to_pubkey, value_to_send, my_pubkey, signing_key, fee=TRANSACTION_FEE): """ This will create a pay-to-public-key transaction, for this function we will assume a constant transaction fee, our protocol will assume no minimum fees. We will create a change output to the sender. """ # first grab all the utxo belonging to my_pubkey, sort utxo ascendingly by value and height utxos = set( sorted(get_utxos_for_addr(my_pubkey), key=lambda utxo: (utxo.value, utxo.height))) total_to_send = value_to_send + fee to_be_spent = [] current_value = 0 for utxo in utxos: to_be_spent.append(utxo) current_value += utxo.value if current_value > total_to_send: # we have all we need to send break txout = TxOut(value=value_to_send, pubkey=to_pubkey) change_amt = sum(utxo.value for utxo in to_be_spent) - total_to_send txout_change = TxOut(value=change_amt, pubkey=my_pubkey) # we need to make txin now based on where we want to send the outputs txins = [] current_value = 0 for utxo in to_be_spent: current_value += utxo.value if current_value > total_to_send: txn = make_txin(signing_key, utxo.outpoint, txout_change) else: txn = make_txin(signing_key, utxo.outpoint, txout) txins.append(txn) if change_amt < 0: raise ValueError(f'insufficient funds {current_value}') return Transaction(txins=txins, txouts=[txout, txout_change])
def __init__(self, prevHash, coinbaseRecipient, txs, nonce, difficulty): self.prevHash = prevHash self.txs = [tx.clone() for tx in txs] self.nonce = nonce self.timestamp = time.time() self.difficulty = difficulty coinbase = Transaction( [], [TxOut(coinbaseRecipient, blockchain.COINBASE_AMT)]) self.txs.insert(0, coinbase)
def __init__(self, reward, miner_address): self.vin_sz = 0 self.vout_sz = 0 self.inputs = [] self.outputs = [] self.hash = None self.timestamp = time.time() txout = TxOut(miner_address, reward) self.outputs.append(txout) self.vout_sz = 1 self.gen_hash()
def generate_next_with_transaction(self, wallet, receiver_address, amount): if not TxOut.is_valid_address(receiver_address): error_payload = {'address': bytes_to_hex(receiver_address)} raise BadRequestError('invalid address', payload=error_payload) if not isinstance(amount, Decimal): error_payload = {'amount': amount} raise BadRequestError('invalid amount', payload=error_payload) coinbase_tx = Transaction.coinbase(wallet.get_public_key(), self.get_latest().index + 1) tx = wallet.create_transaction(receiver_address, amount, self.unspent_tx_outs, self.tx_pool) block_data = [coinbase_tx, tx] return self.generate_raw_next_block(block_data)
class Blockchain(object): def __init__(self): self._blockchain = [self.get_genesis_block()] self.difficulty_bits = 15 self.unspent_tx_outs = process_transactions([self.genesis_transaction], [], 0) @property def blocks(self): return self._blockchain def get_unspent_tx_outs(self): return self.unspent_tx_outs def set_unspent_tx_outs(self, new_utxo): print('replacing unspent_tx_outs with: %s' % new_utxo) self.unspent_tx_outs = new_utxo @blocks.setter def blocks(self, blocks): self._blockchain = blocks # genesis_transaction = {'tx_ins': [{'signature': '', 'tx_out_id': '', 'tx_out_index': 0}], # 'tx_outs': [{ # 'address': getPublicFromWallet(), # 'amount': 50 # }] # 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' # } genesis_transaction = Transaction([TxIn('', 0, '')], [TxOut(get_public_from_wallet(), 50)]) @classmethod def get_genesis_block(cls): # SHA256.new(data=(str(0) + "0"+ str(1465154705) +"my genesis block!!").encode()).hexdigest() return Block(0, "0", 1465154705, cls.genesis_transaction, 0, 0, "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7") def generate_next_block(self, block_data): previous_block = self.get_latest_block() next_index = previous_block.index + 1 next_timestamp = datetime.now().strftime("%s") next_hash, next_nonce = self.calculate_hash(next_index, previous_block.hash, next_timestamp, block_data) new_block = Block(next_index, previous_block.hash, next_timestamp, block_data, self.difficulty_bits, next_nonce, next_hash) if self.add_block(new_block): # broadcastLatest(); return new_block # gets the unspent transaction outputs owned by the wallet def get_my_utxos(self): return find_unspent_tx_outs(get_public_from_wallet(), self.get_unspent_tx_outs()) def construct_next_block(self): coinbase_tx = get_coinbase_transaction(get_public_from_wallet(), self.blocks[-1].index + 1) block_data = [coinbase_tx] + get_transaction_pool() return self.generate_next_block(block_data) def construct_next_block_with_transaction(self, receiver_address, amount): if not is_valid_address(receiver_address): print('invalid address') return if not isinstance(amount, int): print('invalid amount') return coinbase_tx = get_coinbase_transaction(get_public_from_wallet(), self.blocks[-1].index + 1) tx = create_transaction(receiver_address, amount, get_private_from_wallet(), self.get_unspent_tx_outs(), get_transaction_pool()) if not tx: return False block_data = [coinbase_tx, tx] return self.generate_next_block(block_data) def get_account_balance(self): return get_balance(get_public_from_wallet(), self.get_unspent_tx_outs()) def send_transaction(self, address, amount): tx = create_transaction(address, amount, get_private_from_wallet(), self.get_unspent_tx_outs(), get_transaction_pool()) add_to_transaction_pool(tx, self.get_unspent_tx_outs()) # broadCastTransactionPool() return tx def get_latest_block(self): try: return self._blockchain[-1] except IndexError as e: return None def calculate_hash_for_block(self, block): return self.calculate_hash(block.index, block.previous_hash, block.timestamp, block.data, block.nonce) def calculate_hash(self, index, previous_hash, timestamp, data, nonce=None): if not nonce: header = str(index) + previous_hash + str(timestamp) + str(data) + str(self.difficulty_bits) return self.proof_of_work(header) else: hash_object = SHA256.new(data=(str(index) + previous_hash + str(timestamp) + str(data) + str(self.difficulty_bits) + str(nonce)).encode()) return hash_object.hexdigest() def proof_of_work(self, header): """Calculates nonce for the block based on the difficulty bits set""" print("Computing nonce for the block...") target = 2 ** (256 - self.difficulty_bits) for nonce in range(max_nonce): hash_result = SHA256.new(data=(str(header) + str(nonce)).encode()).hexdigest() if int(hash_result, 16) < target: print("Success with nonce %d" % nonce) print("Hash is %s" % hash_result) return (hash_result, nonce) print("Failed after %d (max_nonce) tries" % nonce) return nonce def add_block(self, new_block): if self.is_valid_new_block(new_block, self.get_latest_block()): ret_val = process_transactions(new_block.data, self.get_unspent_tx_outs(), new_block.index) if ret_val is None: print('block is not valid in terms of transactions') return False else: self._blockchain.append(new_block) self.set_unspent_tx_outs(ret_val) update_transaction_pool(self.get_unspent_tx_outs()) return True def is_valid_new_block(self, new_block, previous_block): if previous_block.index + 1 != new_block.index: logger.warning('invalid index') return False if previous_block.hash != new_block.previous_hash: logger.warning('invalid previous hash') return False if self.calculate_hash_for_block(new_block) != new_block.hash: logger.info(str(type(new_block.hash)) + ' ' + str(type(self.calculate_hash_for_block(new_block)))) logger.warning('invalid hash: ' + self.calculate_hash_for_block(new_block) + ' ' + new_block.hash) return False return True def is_valid_chain(self, blockchain_to_validate): # if self.calculate_hash_for_block(Block(**blockchain_to_validate[0])) != self.get_genesis_block().hash: # return False temp_blocks = [Block(**blockchain_to_validate[0])] for currentBlock in blockchain_to_validate[1:]: if self.is_valid_new_block(Block(**currentBlock), temp_blocks[-1]): temp_blocks.append(Block(**currentBlock)) else: return False return True
def buildTxOuts(senderLegacyAddress, receiverLegacyAddress, initialBalance, amount, fee): return [TxOut(utils.addressToScriptPubKey(receiverLegacyAddress), amount), \ TxOut(utils.addressToScriptPubKey(senderLegacyAddress), initialBalance - amount - fee)]
def fromJSON(j): blockchain = Blockchain() jsonChain = json.loads(j) # copy over blocks newBlocks = [] for block in jsonChain['blocks']: newBlockTxs = [] for tx in block['txs']: newBlockTxIns = [] newBlockTxOuts = [] for txIn in tx['txIns']: newBlockTxIn = TxIn(txIn['prevTxHash'], txIn['prevTxOutIndex']) newBlockTxIn.signature = eval(txIn['signature']) newBlockTxIns.append(newBlockTxIn) for txOut in tx['txOuts']: if txOut['address'] == None: newPubKey = None else: newPubKey = PubKey.wrap(txOut['address']) newBlockTxOut = TxOut(newPubKey, txOut['value']) newBlockTxOut.txHash = txOut['txHash'] newBlockTxOut.idx = txOut['idx'] newBlockTxOuts.append(newBlockTxOut) newBlockTx = Transaction(newBlockTxIns, newBlockTxOuts) newBlockTx.timestamp = tx['timestamp'] newBlockTxs.append(newBlockTx) coinbaseRecipientDict = block['txs'][0]['txOuts'][0]['address'] if coinbaseRecipientDict == None: coinbaseRecipient = None else: coinbaseRecipient = PubKey.wrap(coinbaseRecipientDict) prevHash = newBlocks[-1].hash() if len(newBlocks) else None newBlock = Block(prevHash, coinbaseRecipient, newBlockTxs, block['nonce'], block['difficulty']) # remove duplicate coinbase transaction newBlock.txs.pop(0) newBlock.timestamp = block['timestamp'] newBlocks.append(newBlock) blockchain.blocks = newBlocks # copy over pool newPoolTxOuts = [] for txOut in jsonChain['pool']['txOuts']: if txOut['address'] == None: newPubKey = None else: newPubKey = PubKey.wrap(txOut['address']) newPoolTxOut = TxOut(newPubKey, txOut['value']) newPoolTxOut.txHash = txOut['txHash'] newPoolTxOut.idx = txOut['idx'] newPoolTxOuts.append(newPoolTxOut) blockchain.pool.txOuts = newPoolTxOuts # don't need to remove duplicate genesis block because everything was replaced return blockchain