コード例 #1
0
    def block_scan(self, start_block, end_block=None, timeout=10, update_latest=False, save_transactions=False, background=False):
        thread_number = int(random.random() * 10000)
        if not self.get_available_lock():
            scanlog.info('Duplicate blockscan, exiting: %s#%s' %
                         (self.network, thread_number))
            count_metrics('scanner.duplicate_blockscanner', {'network': self.network.nickname})
            return

        scanlog.info('Starting blockscan: %s#%s' %
                     (self.network, thread_number))
        start = time.time()
        end = start + timeout
        next_block = start_block
        while time.time() < end:
            elapsed = time.time() - start
            current_block = self.network.current_block()
            count_metrics('scanner.blocks_behind', {'network': self.network.nickname}, max(current_block - next_block, 0))
            if next_block > current_block:
                scanlog.info('Ending blockscan#%s [%s]: No more %s blocks!' % (
                    thread_number, elapsed, self.network))
                count_metrics('scanner.end_blockscan', {'network': self.network.nickname, 'reason': 'no_more_blocks'}, elapsed, 'Seconds')
                self.release_lock()
                return
            if end_block and next_block > end_block:
                scanlog.info('Ending blockscan#%s [%s]: Reached endblock!' % (
                    thread_number, elapsed))
                count_metrics('scanner.end_blockscan', {'network': self.network.nickname, 'reason': 'reached_endblock'}, elapsed, 'Seconds')
                self.release_lock()
                return

            if background:
                from .tasks import async_process_block
                async_process_block(self.id, next_block)
            else:
                self.process_block(next_block, save_transactions=save_transactions)

            if update_latest:
                self.latest_block = next_block
                self.save()

            next_block += 1

        elapsed = time.time() - start

        # Mail an admin if we run out of scanblock time
        scanlog.info('Ending blockscan#%s [%s]: Out of time!' % (
            thread_number, elapsed))
        count_metrics('scanner.end_blockscan', {'network': self.network.nickname, 'reason': 'out_of_time'}, elapsed, 'Seconds')
        self.release_lock()
        sys.exit()
コード例 #2
0
 def send_notification(self, subject, body):
     sent = 0
     for email in self.notify_email.split(','):
         try:
             send_mail(
                 subject,
                 body,
                 '*****@*****.**',
                 [email.strip()],
             )
             count_metrics('tx.notify_email_success',
                           {'network': self.network.nickname})
             sent += 1
         except Exception as e:
             count_metrics('tx.notify_email_error',
                           {'network': self.network.nickname})
     return sent
コード例 #3
0
    def process_block(self, block_number, save_transactions=False):
        transactions = list(
            self.network.driver.find_transactions(block_number))

        scanlog.info('Processing block: %s @ %s - %s transactions' % (
            self.network, block_number, len(transactions)))

        if save_transactions:
            import json
            fh = open('tests/transactions/block-%s.json' % block_number, 'w+')
            json.dump(transactions, fh, indent=2)

        
        self.process_transactions(transactions)
        
        # At the very end
        count_metrics('scanner.process_block', {'network': self.network.nickname})
コード例 #4
0
ファイル: models.py プロジェクト: oohmygaud/txgun-backend
    def do_lookup(cls, asset, currency='USD'):
        if asset == 'ETH':
            url = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest'
            count_metrics('api.coinmarketcap_get_price')
            parameters = {'symbol': asset, 'convert': currency}
            headers = {
                'Accepts': 'application/json',
                'X-CMC_PRO_API_KEY': settings.CMC_API_KEY
            }

            session = Session()
            session.headers.update(headers)

            try:
                response = session.get(url, params=parameters)
                data = json.loads(response.text)
                return data['data'][asset]['quote'][currency]['price']
            except (ConnectionError, Timeout, TooManyRedirects) as e:
                print(e)
コード例 #5
0
 def process_transactions(self, transactions):
     from tritium.apps.subscriptions.models import Subscription
     from tritium.apps.contracts.models import ERC20
     count = 0
     for tx in transactions:
         count += 1
         tx_timer = time.time()
         if self.in_watch_cache(tx):
             scanlog.debug('Found transaction: %s' % tx)
             find_subscribers = (
                 models.Q(watched_address__iexact=tx['to']) |
                 models.Q(watched_address__iexact=tx['from'])
             )
             if(tx['isToken']):
                 find_subscribers = (
                     find_subscribers |
                     models.Q(watched_address__iexact=tx['tokenTo'])
                 )
             subscriptions = Subscription.objects.filter(find_subscribers)
             #count_metrics('scanner.timers.filter_subscriptions', {'network': self.network.nickname}, time.time() - tx_timer, 'Seconds')
             for subscription in subscriptions:
                 subscription_timer = time.time()
                 subscription.found_transaction(tx)
                 #count_metrics('scanner.timers.found_transaction', {'network': self.network.nickname}, time.time() - subscription_timer, 'Seconds')
             if tx.get('isToken'):
                 token_timer = time.time()
                 try:
                     ERC20.DISCOVERED_TOKEN(self.network, tx['to'])
                     #count_metrics('scanner.token_discovered', {'network': self.network.nickname})
                     #count_metrics('scanner.timers.discover_token', {'network': self.network.nickname}, time.time() - token_timer, 'Seconds')
                 except Exception as e:
                     from tritium.apps.errors.models import ErrorLog
                     ErrorLog.WARNING('Error importing token',
                                      str(e),
                                      transaction=tx['hash']
                                      )
                     scanlog.error('Error importing token %s' % e)
                     #count_metrics('scanner.token_import_error', {'network': self.network.nickname})
                     #count_metrics('scanner.timers.discover_token_error', {'network': self.network.nickname}, time.time() - token_timer, 'Seconds')
         #count_metrics('scanner.timers.whole_process', {'network': self.network.nickname}, time.time() - tx_timer, 'Seconds')
     count_metrics('scanner.process_transactions', {'network': self.network.nickname}, count)
コード例 #6
0
    def found_transaction(self, tx):
        from tritium.apps.contracts.models import PriceLookup, Contract
        # Too noisy, getting expensive
        #log.info('Found transaction: %s' % tx)

        credits = 0
        charges = []

        if self.status == 'paused':
            log.debug('Subscription is paused, skipping transaction')
            count_metrics('tx.subscription_paused',
                          {'network': self.network.nickname})
            return

        if SubscribedTransaction.objects.filter(tx_hash=tx['hash'],
                                                subscription=self):
            log.debug('Already seen this transaction before, skipping')
            count_metrics('tx.duplicate_transaction',
                          {'network': self.network.nickname})
            return

        if not 'datetime' in tx:
            log.error('WHAT THE HELL GUY, NO DATETIME')
            count_metrics('tx.error_missing_datetime',
                          {'network': self.network.nickname})
            return

        parameters = None
        if tx['hasData'] and self.specific_contract_calls:
            contract = Contract.LOOKUP(tx['to'])
            w3c = contract.get_web3_contract()
            function = w3c.get_function_by_selector(tx['input'][:10])
            if function.fn_name not in self.abi_methods.split(','):
                log.debug('Not watching this function: %s' % function.fn_name)
                count_metrics('tx.function_not_watched',
                              {'network': self.network.nickname})
                return
            else:
                charges.append('Method: %s' % function.fn_name)
                credits += settings.SPECIFIC_CALLS_CREDIT_COST
                parameters = {
                    'abi': function.abi,
                    'values': w3c.decode_function_input(tx['input'])[1]
                }

        else:
            if self.watch_token_transfers == False:
                if tx['isToken']:
                    log.debug(
                        'Its a token transaction and we arent watching tokens, skip'
                    )
                    count_metrics('tx.tokens_not_watched',
                                  {'network': self.network.nickname})
                    return
            else:
                if tx['isToken']:
                    credits += settings.TOKEN_TRANSFERS_CREDIT_COST
                    charges.append('Token Transaction')

        if self.include_pricing_data:
            credits += settings.PRICING_DATA_CREDIT_COST
            charges.append('Pricing Data')
            price_info = PriceLookup.get_latest('ETH')
        else:
            price_info = None

        stx = SubscribedTransaction.objects.create(
            subscription=self,
            created_at=tx['datetime'],
            block_hash=tx['blockHash'],
            block_number=tx['blockNumber'],
            from_address=tx['from'],
            gas=tx['gas'],
            gas_price=tx['gasPrice'],
            tx_hash=tx['hash'],
            tx_input=tx['input'],
            nonce=tx['nonce'],
            to_address=tx['to'],
            transaction_index=tx['transactionIndex'],
            value=tx['value'],
            has_data=tx['hasData'],
            is_token=tx['isToken'],
            token_amount=tx.get('tokenAmount', 0),
            token_to=tx.get('tokenTo', ''),
            price_lookup=price_info,
            parameters_json=parameters and json.dumps(parameters) or None)

        tx.pop('datetime', '')  # not serializable

        output = {
            'transaction': stx.serialize(),
            'subscription': self.serialize()
        }

        if self.notify_url and self.realtime_webhooks:
            log.debug('Webhook TX Notification to %s' % self.notify_url)
            try:
                r = requests.post(self.notify_url, json=output)
                log.debug('Webhook response: %s' % r.content)
                count_metrics('tx.notify_webhook_success',
                              {'network': self.network.nickname})
                credits += settings.NOTIFICATION_CREDIT_COST
                charges.append('Webhook')
            except Exception as e:
                count_metrics('tx.notify_webhook_error',
                              {'network': self.network.nickname})

        if self.notify_email and self.realtime_emails:
            log.debug('Email TX Notification to %s' % self.notify_email)

            sent = self.send_notification(
                '%s: Transaction Received' % self.nickname,
                json.dumps(output, indent=2))

            credits += settings.NOTIFICATION_CREDIT_COST * sent
            charges.append('Real-time Email')

        if self.low_balance_warning:
            balance = self.network.get_balance(self.watched_address)
            spent = stx.value + stx.gas * stx.gas_price
            if balance <= spent * 10:
                self.send_notification(
                    '%s: Low Balance' % self.nickname,
                    'The balance of address %s is too low to sustain transactions of size %s; %s remaining'
                    % (self.watched_address, spent, balance / 10E18))

        reason = ('Transaction [%s]: ' % self.nickname) + ','.join(charges)
        if not self.user.subtract_credit(credits, reason):
            self.status = 'paused'
            self.save()
コード例 #7
0
ファイル: models.py プロジェクト: oohmygaud/txgun-backend
def get_etherscan_abi(address):
    count_metrics('api.get_etherscan_abi')
    url = settings.ETHSCAN_URL + 'module=contract&action=getabi&address=' + address
    response = requests.get(url)
    return json.loads(response.content)['result']