def is_valid_transaction_chain(chain): """ Enforce the rules of a chain composed of blocks of transactions. - Each transaction must only appear once in the chain. - There can be one mining reward per block. - Each transaction must be valid. """ transaction_ids = set() for i in range(len(chain)): block = chain[i] has_mining_reward = False for transaction_json in block.data: transaction = Transaction.from_json(transaction_json) if transaction.id in transaction_ids: raise Exception( f'Transaction: {transaction.id} is not unique') transaction_ids.add(transaction.id) if transaction.input == MINING_REWARD_INPUT: if has_mining_reward: raise Exception( 'There can only be one mining reward per block.'\ f'Check block with hash: {block.hash}' ) has_mining_reward = True else: historic_blockchain = Blockchain() historic_blockchain.chain = chain[0:i] historic_balance = Wallet.calculate_balance( historic_blockchain, transaction.input['address']) if historic_balance != transaction.input['amount']: raise Exception( f'Transaction {transaction.id} has an invalid '\ 'input amount') Transaction.is_valid_transaction(transaction)
def message(self, pubnub, message_object): print( f'\n-- Channel: {message_object.channel} | Message: {message_object.message}' ) if message_object.channel == CHANNELS['BLOCK']: block = Block.from_json(message_object.message) # [:] -> all the elements in the array, in that case all blocks in chain potential_chain = self.blockchain.chain[:] potential_chain.append(block) try: self.blockchain.replace_chain(potential_chain) self.transaction_pool.clear_blockchain_transactions( self.blockchain) print('\n -- Successfully replaced the local chain') except Exception as e: print(f'\n -- Did not replace chain: {e}') elif message_object.channel == CHANNELS['TRANSACTION']: transaction = Transaction.from_json(message_object.message) self.transaction_pool.set_transaction(transaction) print('\n -- Set the new transaction in the transaction pool')