Beispiel #1
0
 def test_transaction_create_invalid_schema(self, mock_is_valid_schema):
     err_message = 'Validation error'
     mock_is_valid_schema.side_effect = Mock(
         side_effect=TransactionError(err_message))
     with self.assertRaises(TransactionError) as err:
         Transaction.create(**self.transaction_info)
         self.assertTrue(mock_is_valid_schema.called)
         self.assertIsInstance(err, TransactionError)
         self.assertIn(err_message, err.message)
Beispiel #2
0
 def test_transaction_create_valid_schema(self, mock_is_valid_schema):
     mock_is_valid_schema.return_value = True
     transaction = Transaction.create(**self.transaction_info)
     self.assertTrue(mock_is_valid_schema.called)
     self.assertIsInstance(transaction, Transaction)
     self.assertTrue(
         all([
             attr in self.transaction.info.keys()
             for attr in self.transaction_info.keys()
         ]))
     self.assertTrue(
         all([
             value in self.transaction.info.values()
             for value in self.transaction_info.values()
         ]))
Beispiel #3
0
    def is_valid_transaction_data(chain: list):
        """
        Perform checks to enforce the consistnecy of transactions data in the chain blocks:
        Each transaction mush only appear once in the chain, there can only be one mining
        reward per block and each transaction must be valid.

        :param list chain: blockchain chain of blocks.
        :raise BlockchainError: on invalid transaction data.
        """
        from src.client.models.transaction import Transaction
        from src.client.models.wallet import Wallet
        transaction_uuids = set()
        for index, block in enumerate(chain, start=0):
            has_reward = False
            for transaction_info in block.data:
                try:
                    transaction = Transaction.create(**transaction_info)
                    Transaction.is_valid(transaction)
                except TransactionError as err:
                    message = f'Invalid transaction. {err.message}.'
                    logger.error(f'[Blockchain] Validation error. {message}')
                    raise BlockchainError(message)

                if transaction.uuid in transaction_uuids:
                    message = f'Repetead transaction uuid found: {transaction.uuid}.'
                    logger.error(f'[Blockchain] Validation error. {message}')
                    raise BlockchainError(message)
                transaction_uuids.add(transaction.uuid)

                address = transaction.input.get('address')
                if address == MINING_REWARD_INPUT.get('address'):
                    if has_reward:
                        message = f'Multiple mining rewards in the same block: {block}.'
                        logger.error(
                            f'[Blockchain] Validation error. {message}')
                        raise BlockchainError(message)
                    has_reward = True
                else:
                    historic_blockchain = Blockchain()
                    historic_blockchain.chain = chain[:index]
                    historic_balance = Wallet.get_balance(
                        historic_blockchain, address)
                    amount = transaction.input.get('amount')
                    if historic_balance != amount:
                        message = f'Address {address} historic balance inconsistency: {historic_balance} ({amount}).'
                        logger.error(
                            f'[Blockchain] Validation error. {message}')
                        raise BlockchainError(message)
Beispiel #4
0
async def transact(data: dict):
    logger.info('[API] POST transact. New transaction.')
    recipient = data.get('recipient')
    amount = data.get('amount')
    transaction = router.transactions_pool.get_transaction(
        router.wallet.address)
    if transaction:
        transaction.update(router.wallet, recipient, amount)
        logger.info(
            f'[API] POST transact. Transaction updated: {transaction}.')
    else:
        transaction = Transaction.create(sender=router.wallet,
                                         recipient=recipient,
                                         amount=amount)
        logger.info(f'[API] POST transact. Transaction made: {transaction}.')
    router.transactions_pool.add_transaction(transaction)
    await router.p2p_server.broadcast_transaction(transaction)
    return {'transaction': transaction}
Beispiel #5
0
 def _generate_transaction(self):
     output = {}
     output[self.wallet.address] = MINING_REWARD
     input = MINING_REWARD_INPUT
     id = uuid.uuid4().int
     return Transaction.create(uuid=id, input=input, output=output)