flo-token-tracking/track-tokens.py

351 lines
13 KiB
Python

import requests
import json
import sqlite3
import argparse
import configparser
import subprocess
# Read configuration
config = configparser.ConfigParser()
config.read('config.ini')
# Read command line arguments
parser = argparse.ArgumentParser(description='Script tracks RMT using FLO data on the FLO blockchain - https://flo.cash')
parser.add_argument('-r', '--reset', nargs='?', const=1, type=int, help='Purge existing db and rebuild it')
args = parser.parse_args()
if config['DEFAULT']['NET'] == 'mainnet':
neturl = 'https://florincoin.info/'
localapi = config['DEFAULT']['FLO_CLI_PATH']
elif config['DEFAULT']['NET'] == 'testnet':
neturl = 'https://testnet.florincoin.info/'
localapi = '{} --testnet'.format(config['DEFAULT']['FLO_CLI_PATH'])
else:
print('NET parameter is wrong')
def listcheck(lst):
for element in lst:
try:
float(element)
except ValueError:
print("values to be transferred aren't in the right format")
return 1
return 0
def startTracking(blockindex, config, conn, c):
string = "{} getblockhash {}".format(localapi, str(blockindex))
response = subprocess.check_output(string, shell=True)
blockhash = response.decode("utf-8")
string = "{} getblock {}".format(localapi, str(blockhash))
response = subprocess.check_output(string, shell=True)
blockinfo = json.loads(response.decode("utf-8"))
for transaction in blockinfo["tx"]:
string = "{} getrawtransaction {} 1".format(localapi, str(transaction))
response = subprocess.check_output(string, shell=True)
data = json.loads(response.decode("utf-8"))
text = data["floData"]
text = text[5:]
comment_list = text.split("#")
if comment_list[0] == config['DEFAULT']['PREFIX']:
print("I just saw "+str(config['DEFAULT']['PREFIX']))
commentTransferAmount = comment_list[1:]
#if not all(isinstance(x, (int, float)) for x in commentTransferAmount):
# print("Values to be transffered aren't in the right format")
# continue
if len(commentTransferAmount) == 0:
print("Value for token transfer has not been specified")
continue
returnval = listcheck(commentTransferAmount)
if returnval == 1:
continue
commentTransferAmount = list(map(float, commentTransferAmount))
inputlist = []
querylist = []
for obj in data["vin"]:
querylist.append([obj["txid"], obj["vout"]])
inputval = 0
inputadd = ''
for query in querylist:
string = "{} getrawtransaction {} 1".format(localapi, str(query[0]))
response = subprocess.check_output(string, shell=True)
content = json.loads(response.decode("utf-8"))
for objec in content["vout"]:
if objec["n"] == query[1]:
inputadd = objec["scriptPubKey"]["addresses"][0]
inputval = inputval + objec["value"]
inputlist = [[inputadd, inputval]]
if len(inputlist) > 1:
print("Program has detected more than one input address ")
print("This transaction will be discarded")
continue
outputlist = []
for obj in data["vout"]:
if obj["scriptPubKey"]["type"] == "pubkeyhash":
if inputlist[0][0] == obj["scriptPubKey"]["addresses"][0]:
continue
temp = []
temp.append(obj["scriptPubKey"]["addresses"][0])
temp.append(obj["value"])
outputlist.append(temp)
print("\n\nInput List")
print(inputlist)
print("\nOutput List")
print(outputlist)
if len(inputlist) > 1:
print("Program has detected more than one input address ")
print("This transaction will be discarded")
continue
c.execute("SELECT sum(transferBalance) FROM transactiontable WHERE address=?" , (inputlist[0][0],))
availableTokens = c.fetchall()
availableTokens = availableTokens[0][0]
if availableTokens is None:
print("The input address dosen't exist in our database ")
elif availableTokens < sum(commentTransferAmount):
print("\nThe transfer amount passed in the comments is more than the user owns\nThis transaction will be discarded\n")
continue
elif availableTokens >= sum(commentTransferAmount):
if len(commentTransferAmount) != len(outputlist):
print("The parameters in the comments aren't enough")
print("This transaction will be discarded")
continue
for i in range(len(commentTransferAmount)):
# if output[0] == inputlist[0][0]:
# continue
c.execute("SELECT * FROM transactiontable WHERE address=?",(inputlist[0][0],))
table = c.fetchall()
pidlst = []
checksum = 0
for row in table:
if checksum >= commentTransferAmount[i]:
break
pidlst.append(row[0])
checksum = checksum + row[3]
balance = commentTransferAmount[i]
c.execute("SELECT sum(transferBalance) FROM transactiontable WHERE address=?", ( outputlist[i][0],))
opbalance = c.fetchall()[0][0]
if opbalance is None:
opbalance = 0
c.execute("SELECT sum(transferBalance) FROM transactiontable WHERE address=?", ( inputlist[0][0],))
ipbalance = c.fetchall()[0][0]
for pid in pidlst:
c.execute("SELECT transferBalance FROM transactiontable WHERE id=?", (pid,))
temp = c.fetchall()
temp = temp[0][0]
if balance <= temp:
c.execute("INSERT INTO transactiontable (address, parentid, transferBalance) VALUES (?,?,?)", (outputlist[i][0],pid,balance))
c.execute("UPDATE transactiontable SET transferBalance=? WHERE id=?", (temp-balance, pid))
## transaction logs section ##
c.execute("SELECT id FROM transactiontable ORDER BY id DESC LIMIT 1")
lastid = c.fetchall()[0][0]
transferDescription = str(balance) + " tokens transferred to " + str(outputlist[i][0]) + " from " + str(inputlist[0][0])
blockchainReference = '{}tx/{}'.format(neturl, str(transaction))
c.execute("""INSERT INTO transferlogs (primaryIDReference, transferDescription, transferIDConsumed, blockchainReference)
VALUES (?,?,?,?)""", ( lastid, transferDescription, pid, blockchainReference))
transferDescription = str(inputlist[0][0]) + " balance UPDATED from " + str(temp) + " to " + str(temp-balance)
blockchainReference = '{}tx/{}'.format(neturl, str(transaction))
c.execute("""INSERT INTO transferlogs (primaryIDReference, transferDescription, blockchainReference)
VALUES (?,?,?)""", ( pid, transferDescription, blockchainReference))
## transaction history table ##
c.execute(
'''INSERT INTO transactionHistory (blockno, fromAddress, toAddress, amount, blockchainReference) VALUES (?,?,?,?,?)''',
(blockindex, inputlist[0][0], outputlist[0][0], str(balance), blockchainReference))
##webpage table section ##
transferDescription = str(commentTransferAmount[i]) + " tokens transferred from " + str(inputlist[0][0]) + " to " + str(outputlist[i][0])
c.execute("""INSERT INTO webtable (transferDescription, blockchainReference)
VALUES (?,?)""", ( transferDescription, blockchainReference))
transferDescription = "UPDATE " + str(outputlist[i][0]) + " balance from " + str(opbalance) + " to " + str(opbalance + commentTransferAmount[i])
c.execute("""INSERT INTO webtable (transferDescription, blockchainReference)
VALUES (?,?)""", ( transferDescription, blockchainReference))
transferDescription = "UPDATE " + str(inputlist[0][0]) + " balance from " + str(ipbalance) + " to " + str(ipbalance - commentTransferAmount[i])
c.execute("""INSERT INTO webtable (transferDescription, blockchainReference)
VALUES (?,?)""", ( transferDescription, blockchainReference))
balance = 0
conn.commit()
elif balance > temp:
c.execute("INSERT INTO transactiontable (address, parentid, transferBalance) VALUES (?,?,?)", (outputlist[i][0], pid, temp ))
c.execute("UPDATE transactiontable SET transferBalance=? WHERE id=?", (0, pid))
##transaction logs section ##
c.execute("SELECT id FROM transactiontable ORDER BY id DESC LIMIT 1")
lastid = c.fetchall()[0][0]
transferDescription = str(temp) + " tokens transferred to " + str(outputlist[i][0]) + " from " + str(inputlist[0][0])
blockchainReference = '{}tx/{}'.format(neturl, str(transaction))
c.execute("""INSERT INTO transferlogs (primaryIDReference, transferDescription, transferIDConsumed, blockchainReference)
VALUES (?,?,?,?)""", ( lastid, transferDescription, pid, blockchainReference))
transferDescription = str() + " balance UPDATED from " + str(temp) + " to " + str(0)
blockchainReference = '{}tx/{}'.format(neturl, str(transaction))
c.execute("""INSERT INTO transferlogs (primaryIDReference, transferDescription, blockchainReference)
VALUES (?,?,?)""", ( pid, transferDescription, blockchainReference))
## transaction history table ##
c.execute(
'''INSERT INTO transactionHistory (blockno, fromAddress, toAddress, amount, blockchainReference) VALUES (?,?,?,?,?)''',
(blockindex, inputlist[0][0], outputlist[0][0], str(balance), blockchainReference))
balance = balance - temp
conn.commit()
def resetDatabase(c, conn):
c.execute("DROP TABLE IF EXISTS transactiontable")
c.execute("""CREATE TABLE transactiontable (
id INTEGER PRIMARY KEY AUTOINCREMENT,
address TEXT,
parentid INT,
transferBalance REAL
)""")
c.execute("DROP TABLE IF EXISTS transferlogs")
c.execute("""CREATE TABLE transferlogs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
primaryIDReference INTEGER,
transferDescription TEXT,
transferIDConsumed INT,
blockchainReference TEXT
)""")
c.execute("DROP TABLE IF EXISTS webtable")
c.execute("""CREATE TABLE webtable (
id INTEGER PRIMARY KEY AUTOINCREMENT,
transferDescription TEXT,
blockchainReference TEXT
)""")
c.execute("DROP TABLE IF EXISTS transactionHistory")
c.execute("""CREATE TABLE transactionHistory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
blockno INT,
fromAddress TEXT,
toAddress TEXT,
amount REAL,
blockchainReference TEXT
)""")
c.execute("DROP TABLE IF EXISTS extra")
c.execute("CREATE TABLE extra ( id INTEGER PRIMARY KEY , lastblockscanned INT)")
conn.commit()
def main():
# Connect to db
conn = sqlite3.connect(config['DEFAULT']['DB_NAME'])
c = conn.cursor()
# get current block height
string = "{} getblockcount".format(localapi)
response = subprocess.check_output(string, shell=True)
current_index = json.loads(response.decode("utf-8"))
print("current_block_height : " + str(current_index))
if args.reset == 1:
resetDatabase(c, conn)
# Read root address
root_address = config['DEFAULT']['ROOT_ADDRESS']
root_init_value = int(config['DEFAULT']['INIT_TOKEN_NO'])
# Find root address's block no
string = "{}ext/getaddress/{}/".format(neturl, str(root_address))
response = requests.get(string)
content = json.loads(response.content.decode("utf-8"))
root_trans_hash = ''
for cur in content["last_txs"]:
if cur["type"] == "vout":
root_trans_hash = cur["addresses"]
break
string = "{} getrawtransaction {} 1".format(localapi, str(root_trans_hash))
response = subprocess.check_output(string, shell=True)
content = json.loads(response.decode("utf-8"))
root_block_hash = content["blockhash"]
string = "{} getblock {}".format(localapi, str(root_block_hash))
response = subprocess.check_output(string, shell=True)
content = json.loads(response.decode("utf-8"))
root_block_index = content["height"]
# root_block_index = 26066
print("root_block_index = " + str(root_block_index))
c.execute("INSERT INTO transactiontable ( address, parentid, transferBalance) VALUES (?,?,?)",
(root_address, 0, root_init_value))
conn.commit()
transferDescription = "Root address = " + str(root_address) + " has been initialized with " + str(
root_init_value) + " tokens"
blockchainReference = '{}tx/'.format(neturl)
c.execute("""INSERT INTO transferlogs (primaryIDReference, transferDescription, transferIDConsumed, blockchainReference)
VALUES (?,?,?,?)""",
(1, transferDescription, 0, blockchainReference))
c.execute(
'''INSERT INTO transactionHistory (blockno, fromAddress, toAddress, amount, blockchainReference) VALUES (?,?,?,?,?)''',
(root_block_index, '', root_address, root_init_value, blockchainReference))
c.execute("INSERT INTO extra (id, lastblockscanned) VALUES (?,?)", (1, root_block_index))
conn.commit()
lastblockscanned = root_block_index
else:
response = requests.get("{}api/getblockcount".format(neturl))
string = "{} getblockcount".format(localapi)
response = subprocess.check_output(string, shell=True)
current_index = json.loads(response.decode("utf-8"))
c.execute("SELECT lastblockscanned FROM extra WHERE id=1")
lastblockscanned = c.fetchall()[0][0]
# run loop and pass blockno
for blockindex in range(lastblockscanned + 1, current_index+1):
if blockindex == 3127800:
print('hi')
print(blockindex)
startTracking(blockindex, config, conn, c)
c.execute("UPDATE extra SET lastblockscanned=? WHERE id=?", (blockindex,1))
conn.commit()
conn.commit()
conn.close()
if __name__ == "__main__":
main()