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 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 update_balance(self, address): balance = utils.btc_balance(address) balance /= self.config["satoshi2btc"] if balance >= 0: query = 'UPDATE btcaddresses SET balance=%f WHERE address="%s"' % ( balance, address) utils.populate_db(self.conn, query) return True return False
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 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 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 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
Base = declarative_base() class User(Base): __tablename__ = 'user' id = Column(Integer, primary_key=True) username = Column(String) password = Column(String) def __repr__(self): return "<User(username='******', password='******')>" % (self.username, self.password) # create the schema Base.metadata.create_all(engine) # prepare a db session session_factory = sessionmaker(bind=engine) # autoflush=True, # autocommit=False, # ) DBSession = scoped_session(session_factory) if __name__ == '__main__': from utils import populate_db # insert birdie_settings.MAX_USERS users into the db populate_db()
def populate(): from utils import populate_db populate_db()
# -*- coding: utf-8 -*- from wsgiref.simple_server import make_server from wsgiref.validate import validator from wsgiref.util import application_uri, request_uri from urls import urls from views import view_404 from utils import populate_db from settigs import DB_NAME def app(environ, start_response): uri = request_uri(environ, include_query=False).replace(application_uri(environ), '') yield urls.get(uri, view_404)(environ, start_response).encode('utf-8') if __name__ == '__main__': populate_db(DB_NAME) with make_server('', 8080, validator(app)) as server: server.serve_forever()
Base = declarative_base() class User(Base): __tablename__ = 'user' id = Column(Integer, primary_key=True) username = Column(String) password = Column(String) def __repr__(self): return "<User(username='******', password='******')>" % ( self.username, self.password) # create the schema Base.metadata.create_all(engine) # prepare a db session session_factory = sessionmaker(bind=engine) # autoflush=True, # autocommit=False, # ) DBSession = scoped_session(session_factory) if __name__ == '__main__': from utils import populate_db # insert birdie_settings.MAX_USERS users into the db populate_db()
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"])))