def run(self): # load config from database self.load_config() utils.info("starting statscollector module") while True: # update exchange rates rates = utils.get_exchange_rates() if rates and len(rates): insertquery = 'INSERT INTO forex (btc2usd, btc2eur, btc2gbp, btc2cad, btc2sgd, btc2jpy, btc2inr) VALUES ("%s", "%s", "%s", "%s", "%s", "%s", "%s")' % ( rates["USD"], rates["EUR"], rates["GBP"], rates["CAD"], rates["SGD"], rates["JPY"], rates["INR"], ) deletequery = 'DELETE FROM forex WHERE fid IN (SELECT fid FROM forex LIMIT 1)' # add latest values utils.populate_db(self.conn, insertquery) # delete first row utils.populate_db(self.conn, deletequery) utils.info("updated forex rates") # update btc address balance rows = utils.search_db(self.conn, 'SELECT address FROM btcaddresses') if rows and len(rows): count = 0 for entry in rows: if self.update_balance(entry[0]): count += 1 utils.info("updated balance for %d tracked addresses" % (count)) # load exchange rates from stats table query = 'SELECT btc2usd FROM forex ORDER BY fid DESC LIMIT 1' rows = utils.search_db(self.conn, query) self.config["exchangerates"]["btc2usd"] = rows[0][0] # summary of all addresses summary = self.address_summary() # lowest|highest balance for ransom/donation recipients # most common sender/receiver # most common sender/receiver for ransom/donation # lowest|highest paying|receiving sender/receiver # highest balance/txs/rcvd/sent ## sleep time.sleep(self.config["statscollectiondelay"]) # reload config from database self.load_config()
def auth(self, sender, arguments): """ user: root auth add|remove handle will add|remove handle in authorized users list """ if self.is_root(sender): try: cmd, handle = arguments.split() if cmd.lower() in ["add", "remove"]: if cmd.lower() == "add": rows = utils.search_db( self.conn, 'SELECT authorizedusers FROM config') authusers = rows[0][0] if handle not in authusers: authusers = authusers.split("|") authusers.append(handle) query = 'UPDATE config SET authorizedusers="%s"' % ( "|".join(authusers)) utils.populate_db(self.conn, query) return "user %s is authorized now" % (handle) else: self.error = "user %s already authorized" % ( handle) return None else: rows = utils.search_db( self.conn, 'SELECT authorizedusers FROM config') authusers = rows[0][0] if handle in authusers: authusers = authusers.split("|") authusers.remove(handle) query = 'UPDATE config SET authorizedusers="%s"' % ( "|".join(authusers)) utils.populate_db(self.conn, query) return "user %s is not authorized now" % (handle) else: self.error = "user %s is not authorized" % (handle) return None else: self.error = "incorrect subcommand for this command: auth %s" % ( arguments) except: import traceback traceback.print_exc() self.error = "incorrect params for this command: auth %s" % ( arguments) return None else: self.error = "user %s is not authorized" % (sender) return None
def add(self, sender, arguments): """ user: root add address name1|name2 #hashtag1|#hashtag2 good|bad|unknown will add new entry and enable tracking|tweeting|txstats by default """ if self.is_root(sender): try: address, names, hashtags, status = arguments.split() rows = utils.search_db( self.conn, 'SELECT address, names, hashtags FROM btcaddresses WHERE address="%s"' % (address)) if rows and len(rows): self.error = "address %s already in database" % (address) return None else: query = 'INSERT INTO btcaddresses (address, names, hashtags, status) VALUES ("%s", "%s", "%s", %d)' % ( address, names, hashtags, self.config["statuses"][status.lower()] if status.lower() in self.config["statuses"] else 0) utils.populate_db(self.conn, query) return "added %s to database (%s, %s, %s)" % ( address, names, hashtags, status.lower()) except: self.error = "incorrect params for this command" return None else: self.error = "user %s is not authorized" % (sender) return None
def remove(self, sender, arguments): """ user: root remove address|name1|hashtag2 will loop over all addresses and remove those that match params """ if self.is_root(sender): try: rows = utils.search_db( self.conn, 'SELECT address, names, hashtags FROM btcaddresses') rmcount = 0 for row in rows: if arguments == row[0] or arguments.lower( ) in row[1].lower() or arguments.lower() in row[2].lower(): query = 'DELETE FROM btcaddresses WHERE address="%s"' % ( row[0]) utils.populate_db(self.conn, query) rmcount += 1 if rmcount: return "deleted %d rows matching pattern: %s" % (rmcount, arguments) else: self.error = "could not find any rows matching pattern: %s" % ( arguments) return None except: import traceback traceback.print_exc() self.error = "incorrect params for this command: remove %s" % ( arguments) return None else: self.error = "user %s is not authorized" % (sender) return None
def search(): query = request.args.get('q', None) if not query: return {'message': 'Query parameter missing'}, 400 results = utils.search_db(query) if results: return results, 200 return {'message': 'No CPUs found matching that search'}, 404
def update(self): rows = utils.search_db( self.conn, 'SELECT txhash, timestamp_human FROM btctransactions') if rows and len(rows): for row in rows: txhash, timestamp_human = row[0], row[1] if timestamp_human: query = 'UPDATE btctransactions SET timestamp_human="%s" WHERE txhash="%s"' % ( timestamp_human.replace("(UTC)", "UTC"), txhash) utils.populate_db(self.conn, query)
def load_apikeys(self): rows = utils.search_db( self.conn, 'SELECT twitterconsumerkey, twitterconsumersecret, twitteraccesskey, twitteraccesssecret from apikeys' ) if rows and rows[0] and len(rows[0]): self.config["twitterconsumerkey"], self.config[ "twitterconsumersecret"], self.config[ "twitteraccesskey"], self.config[ "twitteraccesssecret"] = rows[0][0], rows[0][1], rows[ 0][2], rows[0][3]
def load_config(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db(self.conn, 'SELECT taskqueue, tweetqueue, generichashtags, ignorehashtags, happyemojis, neutralemojis, sademojis, queuemonitordelay from config') try: if rows and rows[0] and len(rows[0]): self.config["taskqueue"], self.config["tweetqueue"], self.config["generichashtags"], self.config["ignorehashtags"], self.config["happyemojis"], self.config["neutralemojis"], self.config["sademojis"], self.config["queuemonitordelay"] = rows[0][0], rows[0][1], rows[0][2], rows[0][3], rows[0][4], rows[0][5], rows[0][6], rows[0][7] else: utils.info("could not load config from database, using old config") self.config = copy.deepcopy(oldconfig) except: self.config = copy.deepcopy(oldconfig)
def load_apikeys(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db(self.conn, 'SELECT twitterconsumerkey, twitterconsumersecret, twitteraccesskey, twitteraccesssecret from apikeys') try: if rows and rows[0] and len(rows[0]): self.config["twitterconsumerkey"], self.config["twitterconsumersecret"], self.config["twitteraccesskey"], self.config["twitteraccesssecret"] = rows[0][0], rows[0][1], rows[0][2], rows[0][3] else: utils.info("could not load config from database, using old config") self.config = copy.deepcopy(oldconfig) except: self.config = copy.deepcopy(oldconfig)
def load_config(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db(self.conn, 'SELECT cmdqueue, mentions from config') try: if rows and rows[0] and len(rows[0]): self.config["cmdqueue"], self.config["mentions"] = rows[0][0], rows[0][1].split("|") else: utils.info("could not load config from database, using old config") self.config = copy.deepcopy(oldconfig) except: self.config = copy.deepcopy(oldconfig)
def load_config(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db(self.conn, 'SELECT txupdatedelay FROM config') try: if rows and rows[0] and len(rows[0]): self.config["txupdatedelay"] = rows[0][0] else: utils.info( "populatetxs:load_config: could not load config from database" ) self.config = copy.deepcopy(oldconfig) except: self.config = copy.deepcopy(oldconfig)
def load_config(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db(self.conn, 'SELECT authorizedusers, tweetqueue, tweetmediaqueue, generichashtags, tweetdelay from config') try: if rows and rows[0] and len(rows[0]): self.config["twitterusers"], self.config["tweetqueue"], self.config["tweetmediaqueue"], self.config["generichashtags"], self.config["tweetdelay"] = rows[0][0], rows[0][1], rows[0][2], rows[0][3], rows[0][4] else: utils.info("could not load config from database, using old config") self.config = copy.deepcopy(oldconfig) except: import traceback traceback.print_exc() self.config = copy.deepcopy(oldconfig)
def update(self): statuses = [2, 1, 0] for status in statuses: rows = utils.search_db( self.conn, 'SELECT address, names, hashtags FROM btcaddresses WHERE status=%d' % (status)) try: if rows and len(rows): self.update_database(rows) except: import traceback traceback.print_exc() pass
def txstats(self, sender, arguments): """ user: root txstats start|stop address|name1|hashtag2 will loop over all addresses and enable|disable stats tweet for those that match params """ if self.is_root(sender): try: cmd, pattern = arguments.split() if cmd.lower() in ["start", "stop"]: rows = utils.search_db( self.conn, 'SELECT address, names, hashtags FROM btcaddresses') trkcount = 0 for row in rows: if pattern == row[0] or pattern.lower( ) in row[1].lower() or pattern.lower() in row[2].lower( ): if cmd.lower() == "start": query = 'UPDATE btcaddresses SET dostats=1 WHERE address="%s"' % ( row[0]) utils.populate_db(self.conn, query) trkcount += 1 else: query = 'UPDATE btcaddresses SET dostats=0 WHERE address="%s"' % ( row[0]) utils.populate_db(self.conn, query) trkcount += 1 if trkcount: return "updated %d rows matching pattern: %s" % ( trkcount, pattern) else: self.error = "could not find any rows matching pattern: %s" % ( pattern) return None else: self.error = "incorrect subcommand for this command: txstats %s" % ( arguments) except: import traceback traceback.print_exc() self.error = "incorrect params for this command: txstats %s" % ( arguments) return None else: self.error = "user %s is not authorized" % (sender) return None
def entries_summary(rows, reporttype, filename, heading, timestamp): summary, hashtags, count = list(), list(), 0 for row in rows: hashtags.append(row[0]) hashtags = list(set(hashtags)) for hashtag in sorted(hashtags): htrows = utils.search_db( self.conn, 'SELECT address, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses WHERE names="%s"' % (hashtag)) if htrows and len(htrows): addresses, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human = len( htrows), 0, 0, 0, 0, 0, None for htrow in htrows: if htrow[1] > 0: txs += htrow[1] rcvd += htrow[2] sent += htrow[3] balance += htrow[4] if lasttx_epoch < htrow[5]: lasttx_epoch = htrow[5] lasttx_human = htrow[6] if txs > 0: count += 1 summary.append({ "id": count, "wallet": hashtag, "addresses": addresses, "txs": txs, "rcvd": "%.2f" % (rcvd), "sent": "%.2f" % (sent), "balance": "%.2f" % (balance), "balanceusd": "%.2f" % (balance * self.config["exchangerates"]["btc2usd"]), "lasttx_human": lasttx_human, })
def load_config(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db( self.conn, 'SELECT tweetqueue, tweetmediaqueue, generichashtags, statscollectiondelay from config' ) try: if rows and rows[0] and len(rows[0]): self.config["tweetqueue"], self.config[ "tweetmediaqueue"], self.config[ "generichashtags"], self.config[ "statscollectiondelay"] = rows[0][0], rows[0][ 1], rows[0][2], rows[0][3] else: utils.info("could not load config from database") self.config = copy.deepcopy(oldconfig) except: self.config = copy.deepcopy(oldconfig)
def update(self, sender, arguments): """ user: root update address|name1|hashtag2 good|bad|unknown will loop over all addresses and update status for those that match params """ if self.is_root(sender): try: pattern, status = arguments.split() if status.lower() in self.config["statuses"]: rows = utils.search_db( self.conn, 'SELECT address, names, hashtags FROM btcaddresses') upcount = 0 for row in rows: if pattern == row[0] or pattern.lower( ) in row[1].lower() or pattern.lower() in row[2].lower( ): query = 'UPDATE btcaddresses SET status=%d WHERE address="%s"' % ( self.config["statuses"][status.lower()], row[0]) utils.populate_db(self.conn, query) upcount += 1 if upcount: return "updated %d rows matching pattern: %s" % ( upcount, pattern) else: self.error = "could not find any rows matching pattern: %s" % ( pattern) return None else: self.error = "incorrect status: %s" % (status) return None except: import traceback traceback.print_exc() self.error = "incorrect params for this command: update %s" % ( arguments) return None else: self.error = "user %s is not authorized" % (sender) return None
def load_config(self): oldconfig = copy.deepcopy(self.config) rows = utils.search_db( self.conn, 'SELECT twitteruser, tweetqueue, cmdqueue, mentions, authorizedusers, queuemonitordelay, rootuser from config' ) try: if rows and rows[0] and len(rows[0]): self.config["twitteruser"], self.config[ "tweetqueue"], self.config["cmdqueue"], self.config[ "mentions"], self.config[ "authorizedusers"], self.config[ "queuemonitordelay"], self.config[ "rootuser"] = rows[0][0], rows[0][1], rows[ 0][2], rows[0][3].split( "|"), rows[0][4].split( "|"), rows[0][5], rows[0][6] else: utils.info( "could not load config from database, using old config") self.config = copy.deepcopy(oldconfig) except: self.config = copy.deepcopy(oldconfig)
def update_database(self, rows): for row in rows: # get blockchain.info tags for current address tags = self.get_tags(row[0]) # get list of all txs for current address txs = self.get_txs(row[0]) if txs: if tags and len(tags): rcvd = txs["total_received"] / self.config["satoshi2btc"] sent = txs["total_sent"] / self.config["satoshi2btc"] balance = txs["final_balance"] / self.config["satoshi2btc"] query = 'UPDATE btcaddresses SET tags="%s", txs=%d, rcvd=%f, sent=%f, balance=%f WHERE address="%s"' % ( "|".join(tags), txs["n_tx"], rcvd, sent, balance, row[0]) else: rcvd = txs["total_received"] / self.config["satoshi2btc"] sent = txs["total_sent"] / self.config["satoshi2btc"] balance = txs["final_balance"] / self.config["satoshi2btc"] query = 'UPDATE btcaddresses SET txs=%d, rcvd=%f, sent=%f, balance=%f WHERE address="%s"' % ( txs["n_tx"], rcvd, sent, balance, row[0]) utils.populate_db(self.conn, query) txcount = 0 for tx in txs["txs"]: # dict to store tx information txinfo = { "source": {}, "destination": {}, "txhash": tx["hash"], "timestamp_epoch": tx["time"], "timestamp_human": utils.epoch_to_human_utc(tx["time"]), "relayip": tx["relayed_by"], "rcvd": 0, "sent": 0, } # check if this tx is already in db if utils.search_db( self.conn, 'SELECT txhash FROM btctransactions WHERE txhash="%s"' % (tx["hash"])): continue # load source addresses and btc values for entry in tx["inputs"]: if entry.get("prev_out", None) and entry["prev_out"].get( "addr", None ) is not None and entry["prev_out"].get( "addr", None) not in txinfo["source"]: txinfo["source"][ entry["prev_out"]["addr"]] = entry["prev_out"][ "value"] / self.config["satoshi2btc"] if utils.search_db( self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (entry["prev_out"]["addr"])): txinfo["sent"] = 1 # load destination addresses and btc values for entry in tx["out"]: if entry.get("addr", None) is not None and entry[ "addr"] not in txinfo["destination"]: txinfo["destination"][entry["addr"]] = entry[ "value"] / self.config["satoshi2btc"] if utils.search_db( self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (entry["addr"])): txinfo["rcvd"] = 1 # a tx with sent and rcvd both set has to be ignored, for now if txinfo["sent"] == 1 and txinfo["rcvd"] == 1: continue # update btcaddresses table with in|out address information alladdresses = utils.all_dict_keys( [txinfo["source"], txinfo["destination"]]) for address in alladdresses: query = 'SELECT inaddresses, outaddresses FROM btcaddresses WHERE address="%s"' % ( address) rows = utils.search_db(self.conn, query) if rows and len(rows) and rows[0] and len(rows[0]): if rows[0][0]: inaddrs = "|".join( list( set( list(txinfo["source"].keys()) + [rows[0][0]]))) else: inaddrs = "|".join( list(set(txinfo["source"].keys()))) if rows[0][1]: outaddrs = "|".join( list( set( list(txinfo["destination"].keys()) + [rows[0][1]]))) else: outaddrs = "|".join( list(set(txinfo["destination"].keys()))) query = 'UPDATE btcaddresses SET inaddresses="%s", outaddresses="%s", lasttx_epoch="%s", lasttx_human="%s" WHERE address="%s"' % ( inaddrs, outaddrs, txinfo["timestamp_epoch"], txinfo["timestamp_human"], address) utils.populate_db(self.conn, query) # update btctransactions table amountbtc, address = 0, None senders = list(txinfo["source"].keys()) for addr in txinfo["source"].keys(): if utils.search_db( self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (addr)): address = addr amountbtc = txinfo["source"][addr] break receivers = list(txinfo["destination"].keys()) for addr in txinfo["destination"].keys(): if utils.search_db( self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (addr)): address = addr amountbtc = txinfo["destination"][addr] break query = 'INSERT INTO btctransactions (txhash, address, timestamp_epoch, timestamp_human, amountbtc, relayip, rcvd, sent, receivers, senders) VALUES ("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s")' % ( txinfo["txhash"], address if address else "", txinfo["timestamp_epoch"], txinfo["timestamp_human"], amountbtc, txinfo["relayip"], txinfo["rcvd"], txinfo["sent"], "|".join(receivers) if receivers and len(receivers) else "", "|".join(senders) if senders and len(senders) else "", ) utils.populate_db(self.conn, query) txcount += 1 if txcount: utils.info("added %d new transactions for %s" % (txcount, row[2]))
def parser(self, message): # load exchange rates from stats table query = 'SELECT btc2usd FROM forex ORDER BY fid DESC LIMIT 1' rows = utils.search_db(self.conn, query) self.config["exchangerates"]["btc2usd"] = rows[0][0] # dict to store tx information txinfo = { "source": {}, "destination": {}, "txhash": message["x"]["hash"], "timestamp_epoch": message["x"]["time"], "timestamp_human": utils.epoch_to_human_utc(message["x"]["time"]), "relayip": message["x"]["relayed_by"], "rcvd": 0, "sent": 0, } # load source addresses and btc values for entry in message["x"]["inputs"]: if entry["prev_out"]["addr"] is not None and entry["prev_out"]["addr"] not in txinfo["source"]: txinfo["source"][entry["prev_out"]["addr"]] = entry["prev_out"]["value"]/self.config["satoshi2btc"] if utils.search_db(self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (entry["prev_out"]["addr"])): txinfo["sent"] = 1 # load destination addresses and btc values for entry in message["x"]["out"]: if entry["addr"] is not None and entry["addr"] not in txinfo["destination"]: txinfo["destination"][entry["addr"]] = entry["value"]/self.config["satoshi2btc"] if utils.search_db(self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (entry["addr"])): txinfo["rcvd"] = 1 # a tx with sent and rcvd both set has to be ignored, for now if txinfo["sent"] == 1 and txinfo["rcvd"] == 1: utils.info("ignored txhash https://blockchain.info/tx/%s" % (txinfo["txhash"])) return # update btcaddresses table with in|out address information alladdresses = utils.all_dict_keys([txinfo["source"], txinfo["destination"]]) for address in alladdresses: query = 'SELECT inaddresses, outaddresses FROM btcaddresses WHERE address="%s"' % (address) rows = utils.search_db(self.conn, query) if rows and len(rows) and rows[0] and len(rows[0]): if rows[0][0]: inaddrs = "|".join(list(set(list(txinfo["source"].keys()) + [rows[0][0]]))) else: inaddrs = "|".join(list(set(txinfo["source"].keys()))) if rows[0][1]: outaddrs = "|".join(list(set(list(txinfo["destination"].keys()) + [rows[0][1]]))) else: outaddrs = "|".join(list(set(txinfo["destination"].keys()))) query = 'UPDATE btcaddresses SET inaddresses="%s", outaddresses="%s", lasttx_epoch="%s", lasttx_human="%s" WHERE address="%s"' % (inaddrs, outaddrs, txinfo["timestamp_epoch"], txinfo["timestamp_human"], address) utils.populate_db(self.conn, query) # update btctransactions table amountbtc, address, senders = 0, None, [] senders = list(txinfo["source"].keys()) for addr in txinfo["source"].keys(): if utils.search_db(self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (addr)): address = addr amountbtc = txinfo["source"][addr] break receivers = list(txinfo["destination"].keys()) for addr in txinfo["destination"].keys(): if utils.search_db(self.conn, 'SELECT address FROM btcaddresses WHERE address="%s"' % (addr)): address = addr amountbtc = txinfo["destination"][addr] break query = 'INSERT INTO btctransactions (txhash, address, timestamp_epoch, timestamp_human, amountbtc, relayip, rcvd, sent, receivers, senders) VALUES ("%s", "%s", %d, "%s", "%s", "%s", "%s", "%s", "%s", "%s")' % ( txinfo["txhash"], address if address else "", txinfo["timestamp_epoch"], txinfo["timestamp_human"], amountbtc, txinfo["relayip"], txinfo["rcvd"], txinfo["sent"], "|".join(receivers) if receivers and len(receivers) else "", "|".join(senders) if senders and len(senders) else "", ) utils.populate_db(self.conn, query) utils.info("added transaction rows to localdb (sent: %s, rcvd: %s)" % (True if txinfo["sent"] else False, True if txinfo["rcvd"] else False)) # add tweet message to tw queue tweet = [] for address in txinfo["source"].keys(): rows = utils.search_db(self.conn, 'SELECT names, balance, hashtags, status FROM btcaddresses WHERE address="%s" AND dotweet=1' % (address)) if rows and len(rows) and rows[0] and len(rows[0]): names, balance, hashtags, status = rows[0][0], rows[0][1], rows[0][2], rows[0][3] self.update_balance(address) balance = balance*self.config["exchangerates"]["btc2usd"] if balance >= 0 else -1 for tag in self.config["ignorehashtags"].split("|"): hashtags = hashtags.replace(tag, "") hashtags = hashtags.strip("|") sender = None if hashtags and hashtags != "": sender = hashtags elif names and names != "": sender = "https://blockchain.info/address/%s (%s)" % (address, names) else: sender = "https://blockchain.info/address/%s" % (address) if status == 0: emoji = random.choice(self.config["neutralemojis"].split("|")) elif status == 1: emoji = random.choice(self.config["happyemojis"].split("|")) elif status == 2: emoji = random.choice(self.config["sademojis"].split("|")) else: emoji = random.choice(self.config["neutralemojis"]) tweet.append("%s sent %f BTC ($%.2f) (https://blockchain.info/tx/%s) %s %s" % ( sender, txinfo["source"][address], txinfo["source"][address]*self.config["exchangerates"]["btc2usd"], txinfo["txhash"], #"(balance: %.02f) " % balance if balance >= 0 else "", self.config["generichashtags"], emoji)) for address in txinfo["destination"].keys(): rows = utils.search_db(self.conn, 'SELECT names, balance, hashtags, status FROM btcaddresses WHERE address="%s" AND dotweet=1' % (address)) if rows and len(rows) and rows[0] and len(rows[0]): names, balance, hashtags, status = rows[0][0], rows[0][1], rows[0][2], rows[0][3] self.update_balance(address) balance = balance*self.config["exchangerates"]["btc2usd"] if balance >= 0 else -1 for tag in self.config["ignorehashtags"].split("|"): hashtags = hashtags.replace(tag, "") hashtags = hashtags.strip("|") receiver = None if hashtags and hashtags != "": receiver = hashtags elif names and names != "": receiver = "https://blockchain.info/address/%s (%s)" % (address, names) else: receiver = "https://blockchain.info/address/%s" % (address) if status == 0: emoji = random.choice(self.config["neutralemojis"].split("|")) elif status == 1: emoji = random.choice(self.config["happyemojis"].split("|")) elif status == 2: emoji = random.choice(self.config["sademojis"].split("|")) else: emoji = random.choice(self.config["neutralemojis"]) tweet.append("%s rcvd %f BTC ($%.2f) (https://blockchain.info/tx/%s) %s %s" % ( receiver, txinfo["destination"][address], txinfo["destination"][address]*self.config["exchangerates"]["btc2usd"], txinfo["txhash"], #"(balance: %.02f) " % balance if balance >= 0 else "", self.config["generichashtags"], emoji)) if tweet and len(tweet): tweet = " ".join(tweet) tweet = utils.unicodecp_to_unicodestr(tweet) utils.enqueue(queuefile=self.config["tweetqueue"], data=tweet) utils.info("%s" % (tweet)) utils.info("added message to queue: %s (%d total)" % (self.config["tweetqueue"], utils.queuecount(queuefile=self.config["tweetqueue"])))
def show(self, sender, arguments): """ user: root, auth show address|name1|hashtag2 will loop over all addresses and generate combined stats for those that match params """ if self.is_root(sender) or self.is_authorized(sender): try: # load exchange rates from stats table rows = utils.search_db( self.conn, 'SELECT btc2usd FROM forex ORDER BY fid DESC LIMIT 1') self.config["exchangerates"]["btc2usd"] = rows[0][0] result, summary, allcount, mtcount, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human = list( ), list(), 0, 0, 0, 0, 0, 0, 0, None skipargscheck = False if arguments.lower() == "all": rows = utils.search_db( self.conn, 'SELECT address, names, hashtags, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses' ) skipargscheck = True elif arguments.lower() == "bad": rows = utils.search_db( self.conn, 'SELECT address, names, hashtags, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses WHERE status=2' ) skipargscheck = True elif arguments.lower() == "good": rows = utils.search_db( self.conn, 'SELECT address, names, hashtags, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses WHERE status=1' ) skipargscheck = True elif arguments.lower() == "unknown": rows = utils.search_db( self.conn, 'SELECT address, names, hashtags, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses WHERE status=0' ) skipargscheck = True if skipargscheck: for row in rows: summary.append("Address: %s" % (row[0])) summary.append("Names: %s" % (row[1])) summary.append("Hashtags: %s" % (row[2])) summary.append("Transactions: %s" % (row[3])) summary.append( "Received: %.2f (%.2f USD)" % (row[4], row[4] * self.config["exchangerates"]["btc2usd"])) summary.append( "Sent: %.2f (%.2f USD)" % (row[5], row[5] * self.config["exchangerates"]["btc2usd"])) summary.append( "Balance: %.2f (%.2f USD)" % (row[6], row[6] * self.config["exchangerates"]["btc2usd"])) summary.append("Last TX: %s" % (row[8])) allcount += 1 # count all txs (value should be >= 0, -1 is used as default while populating database initially) if row[3] >= 0: mtcount += 1 # use only those addresses that have atleast 1 or more txs if row[3] > 0: txs += row[3] rcvd += row[4] sent += row[5] balance += row[6] summary.append("---") else: rows = utils.search_db( self.conn, 'SELECT address, names, hashtags, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses' ) for row in rows: if arguments == row[0] or arguments.lower( ) in row[1].lower() or arguments.lower( ) in row[2].lower(): summary.append("Address: %s" % (row[0])) summary.append("Names: %s" % (row[1])) summary.append("Hashtags: %s" % (row[2])) summary.append("Transactions: %s" % (row[3])) summary.append( "Received: %.2f (%.2f USD)" % (row[4], row[4] * self.config["exchangerates"]["btc2usd"])) summary.append( "Sent: %.2f (%.2f USD)" % (row[5], row[5] * self.config["exchangerates"]["btc2usd"])) summary.append( "Balance: %.2f (%.2f USD)" % (row[6], row[6] * self.config["exchangerates"]["btc2usd"])) summary.append("Last TX: %s" % (row[8])) allcount += 1 # count all txs (value should be >= 0, -1 is used as default while populating database initially) if row[3] >= 0: mtcount += 1 # use only those addresses that have atleast 1 or more txs if row[3] > 0: txs += row[3] rcvd += row[4] sent += row[5] balance += row[6] summary.append("---") summary.append("\n") summary.append("Matches: %d" % (mtcount)) summary.append("Transactions: %d" % (txs)) summary.append( "Received: %.2f (%.2f USD)" % (rcvd, rcvd * self.config["exchangerates"]["btc2usd"] if rcvd >= 0 else -1)) summary.append( "Sent: %.2f (%.2f USD)" % (sent, sent * self.config["exchangerates"]["btc2usd"] if sent >= 0 else -1)) summary.append( "Balance: %.2f (%.2f USD)" % (balance, balance * self.config["exchangerates"]["btc2usd"] if balance >= 0 else -1)) if mtcount > 0: return "\n".join(summary) elif allcount > 0: self.error = "could not find any txs for pattern: %s" % ( arguments) return None else: self.error = "could not find any rows matching pattern: %s" % ( arguments) return None except: import traceback traceback.print_exc() self.error = "incorrect params for this command: show %s" % ( arguments) return None else: self.error = "user %s is not authorized" % (sender) return None
def address_summary(self): def write_file(filename, data): with open(filename, "w") as file: file.write(data) def entries_summary(rows, reporttype, filename, heading, timestamp): summary, hashtags, count = list(), list(), 0 for row in rows: hashtags.append(row[0]) hashtags = list(set(hashtags)) for hashtag in sorted(hashtags): htrows = utils.search_db( self.conn, 'SELECT address, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human FROM btcaddresses WHERE names="%s"' % (hashtag)) if htrows and len(htrows): addresses, txs, rcvd, sent, balance, lasttx_epoch, lasttx_human = len( htrows), 0, 0, 0, 0, 0, None for htrow in htrows: if htrow[1] > 0: txs += htrow[1] rcvd += htrow[2] sent += htrow[3] balance += htrow[4] if lasttx_epoch < htrow[5]: lasttx_epoch = htrow[5] lasttx_human = htrow[6] if txs > 0: count += 1 summary.append({ "id": count, "wallet": hashtag, "addresses": addresses, "txs": txs, "rcvd": "%.2f" % (rcvd), "sent": "%.2f" % (sent), "balance": "%.2f" % (balance), "balanceusd": "%.2f" % (balance * self.config["exchangerates"]["btc2usd"]), "lasttx_human": lasttx_human, }) # add this to html report template #env = jinja2.Environment(loader=jinja2.FileSystemLoader(self.config["templatedir"]), **self.config["templateopts"]) #env.trim_blocks = True #env.lsrtip_blocks = True #write_file("%s/%s" % (self.config["htmldir"], filename), env.get_template("stats.template.html").render(entries=summary, reporttype=reporttype, heading=heading, timestamp=timestamp)) ## render html as an image and save to disk #webbrowser.open_new("%s/%s" % (self.config["htmldir"], filename)) #time.sleep(self.config["imagesavedelay"]) ## read image data, add to tweetmedia queue, delete image file #try: # with open("%s/stats.png" % (self.config["downloaddir"]), "rb") as fo: # imgdata = fo.read() # utils.enqueue(queuefile=self.config["tweetmediaqueue"], data=imgdata) # utils.info("added image data to queue") #except Exception as ex: # utils.warn(ex) #utils.remove_file("%s/stats.png" % (self.config["downloaddir"])) timestamp = "%s UTC" % (utils.current_datetime_utc_string()) rows = utils.search_db( self.conn, 'SELECT names FROM btcaddresses WHERE dostats=1 AND status=1') if rows and len(rows): entries_summary(rows, "good", "stats-donation.html", self.config["heading_good"], timestamp) rows = utils.search_db( self.conn, 'SELECT names FROM btcaddresses WHERE dostats=1 AND status=2') if rows and len(rows): entries_summary(rows, "bad", "stats-ransom.html", self.config["heading_bad"], timestamp)