def test_get_metrics(self, mocker, blockchain_sync, processor, db_session, persistence_module: SQLPersistenceInterface): # Generate dummy activity for metrics tf1 = blockchain_sync.add_transaction_filter( '0x000090c5a236130E5D51260A2A5Bfde834C694b6', self.contract_type, self.filter_parameters, self.filter_type, self.decimals, self.block_epoch).id tf2 = blockchain_sync.add_transaction_filter( '0x000090c5a236130E5D51260A2A5Bfde844C694b6', self.contract_type, self.filter_parameters, self.filter_type, self.decimals, self.block_epoch).id success_tx = BlockchainTransaction( _status='PENDING', block=10, hash='0x4444444444444444444444444', contract_address=self.contract_address, is_synchronized_with_app=False, recipient_address='0x3333333333333333333333333', sender_address='0x2222222222222222222222222', amount=10, is_third_party_transaction=True) db_session.add(success_tx) fail_tx = BlockchainTransaction( _status='PENDING', block=10, hash='0x4444444444444444444444445', contract_address=self.contract_address, is_synchronized_with_app=True, recipient_address='0x3333333333333333333333334', sender_address='0x2222222222222222222222223', amount=10, is_third_party_transaction=True) db_session.add(fail_tx) expected_resp = { 'unsynchronized_transaction_count': { '0x468F90c5a236130E5D51260A2A5Bfde834C694b6': 1 }, 'synchronized_transaction_count': { '0x468F90c5a236130E5D51260A2A5Bfde834C694b6': 1 }, 'last_time_synchronized': None } # Check base metrics resp = blockchain_sync.get_metrics() resp['last_time_synchronized'] = None assert resp == expected_resp # Check failed callbacks failed_callbacks = blockchain_sync.get_failed_callbacks() expected_resp = { '0x468F90c5a236130E5D51260A2A5Bfde834C694b6': ['0x4444444444444444444444444'] } assert failed_callbacks == expected_resp
def second_dummy_transaction(db_session, dummy_task, dummy_wallet): from sql_persistence.models import BlockchainTransaction txn = BlockchainTransaction(signing_wallet=dummy_wallet) txn.task = dummy_task db_session.add(txn) db_session.commit() return txn
def test_transaction_status_propagation(self, db_session): task = BlockchainTask(uuid=str_uuid()) assert task.status == 'UNSTARTED' transaction_1 = BlockchainTransaction() transaction_1.task = task transaction_1.status = 'PENDING' assert task.status == 'PENDING' transaction_2 = BlockchainTransaction() transaction_2.task = task transaction_2.status = 'SUCCESS' assert task.status == 'SUCCESS' assert task.status_code == 1 db_session.add_all([task, transaction_1, transaction_2]) db_session.commit() # Uses a custom expression so worth testing the filter queried_task = db_session.query(BlockchainTask).filter( BlockchainTask.status == 'SUCCESS').first() assert queried_task == task
def created_nonced_transaction(): t = BlockchainTransaction( first_block_hash=persistence_module.first_block_hash) t.signing_wallet = wallet db_session.add(t) db_session.commit() nonce = persistence_module.locked_claim_transaction_nonce( network_nonce=starting_nonce, signing_wallet_id=wallet.id, transaction_id=t.id) t.nonce_consumed = True return t, nonce
def create_blockchain_transaction(self, task_uuid): task = session.query(BlockchainTask).filter_by(uuid=task_uuid).first() blockchain_transaction = BlockchainTransaction( signing_wallet=task.signing_wallet, first_block_hash=self.first_block_hash) session.add(blockchain_transaction) if task: blockchain_transaction.task = task session.commit() return blockchain_transaction
def test_force_recall_webhook(self, mocker, blockchain_sync, processor, db_session, persistence_module: SQLPersistenceInterface): fail_tx = BlockchainTransaction( _status='PENDING', block=10, hash='0x4444444444444444444444445', contract_address=self.contract_address, is_synchronized_with_app=False, recipient_address='0x3333333333333333333333334', sender_address='0x2222222222222222222222223', amount=10, is_third_party_transaction=True) db_session.add(fail_tx) class RequestsResp(): ok = True assert fail_tx.is_synchronized_with_app == False def check_correct_webhook_call(transaction): assert transaction == fail_tx return RequestsResp() mocker.patch.object(blockchain_sync, 'call_webhook', check_correct_webhook_call) blockchain_sync.force_recall_webhook('0x4444444444444444444444445') assert fail_tx.is_synchronized_with_app == True
def _claim_transaction_nonce( self, network_nonce: int, signing_wallet: BlockchainWallet, transaction: BlockchainTransaction, ) -> int: if transaction.nonce is not None: return transaction.nonce calculated_nonce = self._calculate_nonce(signing_wallet, network_nonce) transaction.signing_wallet = signing_wallet transaction.nonce = calculated_nonce transaction.status = 'PENDING' # TODO: can we shift this commit out? self.session.commit() return calculated_nonce
def create_blockchain_transaction(self, task_uuid): task = self.session.query(BlockchainTask).filter_by( uuid=task_uuid).first() blockchain_transaction = BlockchainTransaction( signing_wallet=task.signing_wallet, first_block_hash=self.first_block_hash) self.session.add(blockchain_transaction) if task: # TODO: when is this ever not the case? # We should just force signing walelt based off the task blockchain_transaction.task = task self.session.commit() return blockchain_transaction
def test_set_transaction_status(self, db_session): transaction = BlockchainTransaction() assert transaction.status == 'UNKNOWN' assert transaction.status_code == 99 transaction.status = 'PENDING' assert transaction.status == 'PENDING' assert transaction.status_code == 2 with pytest.raises(ValueError): transaction.status = 'NOT_A_STATUS' db_session.add(transaction) db_session.commit() # Uses a custom expression so worth testing the filter queried_transaction = db_session.query(BlockchainTransaction).filter( BlockchainTransaction.status_code == 2).first() assert queried_transaction == transaction
def test_update_transaction_data( self, db_session, persistence_module: SQLPersistenceInterface): transaction = BlockchainTransaction() db_session.add(transaction) db_session.commit() persistence_module.update_transaction_data(transaction.id, { 'status': 'SUCCESS', 'ignore': True }) assert transaction.status == 'SUCCESS' assert transaction.ignore is True
def create_external_transaction(self, status, block, hash, contract_address, is_synchronized_with_app, recipient_address, sender_address, amount): transaction_object = BlockchainTransaction( _status = status, block = block, hash = hash, contract_address = contract_address, is_synchronized_with_app = is_synchronized_with_app, recipient_address = recipient_address, sender_address = sender_address, amount = amount, is_third_party_transaction = True # External transaction will always be third party ) self.session.add(transaction_object) self.session.commit() return transaction_object
def test_handle_event(self, mocker, blockchain_sync, processor, persistence_module: SQLPersistenceInterface): # Create dummy objects for this functions to consume (handle_event only uses decimals) class DummyFilter(): decimals = 18 filt = DummyFilter() class RequestsResp(): ok = True # Check if handle_event halts (returns true) if there's already a synchronized transaction # with the same ID in the DB t = self.Transaction(10, '0x1111111111111111111111111111', self.contract_address, True, '0x2222222222222222222222222', '0x3333333333333333333333333', 10) tx = BlockchainTransaction( _status='PENDING', block=10, hash='0x5555555555555555555555555', contract_address=self.contract_address, is_synchronized_with_app=False, recipient_address='0x3333333333333333333333333', sender_address='0x2222222222222222222222222', amount=10, is_third_party_transaction=True) # If the webhook call doesn't work, it does not call mark_as_completed def check_correct_webhook_call_fail(transaction): assert transaction == tx resp = RequestsResp() resp.ok = False return resp # from celery_app import persistence_module as pm pm = persistence_module mocker.patch.object(blockchain_sync, 'call_webhook', check_correct_webhook_call_fail) mocker.patch.object(pm, 'get_transaction', lambda hash: tx) mocker.patch.object(pm, 'create_external_transaction', lambda *args, **kwargs: tx) mark_as_completed_mock = mocker.patch.object( pm, 'mark_transaction_as_completed') result = blockchain_sync.handle_event(t, filt) assert result == True blockchain_sync.handle_event(t, filt) # Make sure mark_as_completed is NOT called assert len(mark_as_completed_mock.call_args_list) == 0 # If the filter isn't already synchronized, create the object and call the webhook mocker.patch.object(pm, 'get_transaction', lambda hash: None) tx = BlockchainTransaction( _status='PENDING', block=10, hash='0x4444444444444444444444444', contract_address=self.contract_address, is_synchronized_with_app=False, recipient_address='0x3333333333333333333333333', sender_address='0x2222222222222222222222222', amount=10, is_third_party_transaction=True) # Make sure call_webhook is called with the right data def check_correct_webhook_call(transaction): assert transaction == tx return RequestsResp() mocker.patch.object(blockchain_sync, 'call_webhook', check_correct_webhook_call) blockchain_sync.handle_event(t, filt) # Make sure mark_as_completed is called assert len(mark_as_completed_mock.call_args_list) == 1