def test_is_tx_valid_when_invalid_outputs(): sender_wallet = Wallet() transaction = Transaction(sender_wallet, "b64e8ac4", 50) transaction.output[sender_wallet.address] = 9001 with pytest.raises(Exception, match="Invalid transaction."): Transaction.is_tx_valid(transaction)
def test_block_reward_tx_when_invalid_reward_amt(): wallet = Wallet() reward_tx = Transaction.generate_reward_transaction(wallet) reward_tx.output[wallet.address] = 100000 with pytest.raises(Exception, match="Invalid block reward transaction."): Transaction.is_tx_valid(reward_tx)
def is_tx_chain_valid(blockchain): """ Validate incoming blockchain comprised of blocks with Tx therein qua the following ruleset: - each Tx occurs once in the blockchain (i.e. 'double spend') - there is only one valid reward Tx per block - transaction obj must be intrinsically valid """ # Tx tracked by id, raise if duplicate tx_tracking_pool = set() # unwrap blockchain, unwrap blocks therein, deserialize ea block's Tx and parse them for i in range(len(blockchain)): block = blockchain[i] mining_reward_extant = False for serialized_tx in block.data: deserialized_tx = Transaction.deserialize_from_json( serialized_tx) # if Tx already exists if (deserialized_tx.id in tx_tracking_pool): raise Exception( f"Transaction {deserialized_tx.id} is not unique; this transaction is therefore invalid." ) # add Tx to tracking pool tx_tracking_pool.add(deserialized_tx.id) # if Tx is a block reward, only validate against reward fields if (deserialized_tx.input == MINING_REWARD_INPUT): if (mining_reward_extant): raise Exception(f""" There can only be one mining reward per block. Evaluation of block with hash: {block.hash} recommended.""" ) mining_reward_extant = True else: # recalc balance after every Tx to prevent input tamper blockchain_provenance = Blockchain() blockchain_provenance.chain = blockchain[0:i] balance_provenance = Wallet.calculate_balance( blockchain_provenance, deserialized_tx.input["address"]) if (balance_provenance != deserialized_tx.input["amount"]): raise Exception( f"Transaction {deserialized_tx.id} contains an invalid input amount." ) # last, run validator to check format Transaction.is_tx_valid(deserialized_tx)
def test_block_reward_tx_when_valid_tx(): reward_tx = Transaction.generate_reward_transaction(Wallet()) Transaction.is_tx_valid(reward_tx)
def test_is_tx_valid(): Transaction.is_tx_valid(Transaction(Wallet(), "b64e8ac4", 50))
def test_block_reward_tx_when_exceeds_recipients(): reward_tx = Transaction.generate_reward_transaction(Wallet()) reward_tx.output["second_and_invalid_recipient"] = 100 with pytest.raises(Exception, match="Invalid block reward transaction."): Transaction.is_tx_valid(reward_tx)