def transaction_chain_is_valid(chain): """ This section deals with enforcing rules of a chain made up of blocks of transactions. The following must apply: - Each transaction must only appear once in the chain. - There can only 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 = SystemTransactions.convert_transaction_data_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.transaction_input == INPUT_FOR_MINING_REWARD: if has_mining_reward: raise Exception( 'There can only be one mining reward given per block.'\ f'Check block with the hash: {block.hash}' ) has_mining_reward = True else: historic_blockchain = Blockchain() historic_blockchain.chain = chain[0:i] historic_balance = Wallet.wallet_balance_calculation( historic_blockchain, transaction.transaction_input['address'] ) if historic_balance != transaction.transaction_input['amount']: raise Exception( f'Transaction {transaction.id} has an invalid '\ 'input amount' ) SystemTransactions.positively_validate_transaction(transaction)