Smart contract integration - Half Done
This commit is contained in:
parent
38a00c9f2e
commit
11a4aa09c6
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
tree.db
|
||||
.idea/
|
||||
flo_addresses.txt
|
||||
__pycache__/
|
||||
*.swp
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1,12 +1,6 @@
|
||||
[DEFAULT]
|
||||
NET = testnet
|
||||
DB_NAME = tree.db
|
||||
ROOT_ADDRESS = FHQ5rPqqMZT4r3oqpecM54E7tieQoJwZTK
|
||||
INIT_TOKEN_NO = 21000000
|
||||
FLO_CLI_PATH = /usr/local/bin/flo-cli
|
||||
START_BLOCK = 461275
|
||||
|
||||
;if 'ranchimalltest#100' is on blockchain, set value to 'ranchimalltest'
|
||||
PREFIX = ranchimall
|
||||
START_BLOCK = 489130
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@ -2,6 +2,7 @@ from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import Column, Integer, Float, String, ForeignKey
|
||||
|
||||
Base = declarative_base()
|
||||
ContractBase = declarative_base()
|
||||
|
||||
class Extra(Base):
|
||||
__tablename__ = "extra"
|
||||
@ -43,4 +44,12 @@ class Webtable(Base):
|
||||
transferDescription = Column('transferDescription', String)
|
||||
blockchainReference = Column('blockchainReference', String)
|
||||
|
||||
class ContractStructure(ContractBase):
|
||||
__tablename__ = "contractstructure"
|
||||
|
||||
id = Column('id', Integer, primary_key=True)
|
||||
attribute = Column('attribute', String)
|
||||
index = Column('index', Integer)
|
||||
value = Column('value', String)
|
||||
|
||||
|
||||
|
||||
123
parsing.py
123
parsing.py
@ -5,6 +5,7 @@ operation = None
|
||||
address = None
|
||||
amount = None
|
||||
|
||||
|
||||
def isTransfer(text):
|
||||
wordlist = ['transfer','send','give'] #keep everything lowercase
|
||||
textList = text.split(' ')
|
||||
@ -22,6 +23,31 @@ def isIncorp(text):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def isSmartContract(text):
|
||||
textList = text.split(' ')
|
||||
for word in textList:
|
||||
if word[-1] == '@':
|
||||
return word
|
||||
return False
|
||||
|
||||
|
||||
def isSmartContractPay(text):
|
||||
wordlist = text.split(' ')
|
||||
if len(wordlist) != 2:
|
||||
return False
|
||||
smartContractTrigger = re.findall(r"smartContractTrigger:'.*'", text)[0].split('smartContractTrigger:')[1]
|
||||
smartContractTrigger = smartContractTrigger[1:-1]
|
||||
smartContractName = re.findall(r"smartContractName:.*@", text)[0].split('smartContractName:')[1]
|
||||
smartContractName = smartContractName[:-1]
|
||||
|
||||
if smartContractTrigger and smartContractName:
|
||||
contractconditions = { 'smartContractTrigger':smartContractTrigger, 'smartContractName':smartContractName }
|
||||
return contractconditions
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def extractOperation(text):
|
||||
operationList = ['send', 'transfer', 'give'] # keep everything lowercase
|
||||
count = 0
|
||||
@ -35,6 +61,7 @@ def extractOperation(text):
|
||||
return returnval
|
||||
|
||||
|
||||
# todo pass marker to the function and support all types
|
||||
def extractAmount(text):
|
||||
count = 0
|
||||
returnval = None
|
||||
@ -61,6 +88,7 @@ def extractMarker(text):
|
||||
return word
|
||||
return False
|
||||
|
||||
|
||||
def extractInitTokens(text):
|
||||
base_units = {'thousand':10**3 , 'million':10**6 ,'billion':10**9, 'trillion':10**12}
|
||||
textList = text.split(' ')
|
||||
@ -74,27 +102,106 @@ def extractInitTokens(text):
|
||||
continue
|
||||
|
||||
|
||||
def extractAddress(text):
|
||||
textList = text.split(' ')
|
||||
for word in textList:
|
||||
if word[-1] == '$':
|
||||
return word
|
||||
return False
|
||||
|
||||
|
||||
def extractContractType(text):
|
||||
operationList = ['betting*'] # keep everything lowercase
|
||||
count = 0
|
||||
returnval = None
|
||||
for operation in operationList:
|
||||
count = count + text.count(operation)
|
||||
if count > 1:
|
||||
return 'Too many'
|
||||
if count == 1 and (returnval is None):
|
||||
returnval = operation
|
||||
return returnval
|
||||
|
||||
|
||||
def extractContractCondition(text):
|
||||
return text.split("contractcondition:")[1][1:-1]
|
||||
|
||||
|
||||
def extractContractConditions(text, contracttype, marker):
|
||||
rulestext = re.split('contractconditions:\s*', text)[-1]
|
||||
rulelist = re.split('\d\.\s*', rulestext)
|
||||
if contracttype == 'betting*':
|
||||
extractedRules = {}
|
||||
for rule in rulelist:
|
||||
if rule=='':
|
||||
continue
|
||||
elif rule[:19]=='userassetcommitment':
|
||||
pattern = re.compile('[^userassetcommitment="].*[^"]')
|
||||
searchResult = pattern.search(rule).group(0)
|
||||
extractedRules['userassetcommitment'] = searchResult.split(marker)[0]
|
||||
elif rule[:17]=='smartcontractpays':
|
||||
conditions = rule.split('smartcontractpays=')[1]
|
||||
if conditions[0]=='"' or conditions[0]=="'" or conditions[-1]=='"' or conditions[-1]=="'":
|
||||
conditionlist = conditions[1:-1].split('|')
|
||||
extractedRules['smartcontractpays'] = {}
|
||||
for idx, condition in enumerate(conditionlist):
|
||||
extractedRules['smartcontractpays'][idx] = condition.strip()
|
||||
else:
|
||||
print("something is wrong with smartcontractpays conditions")
|
||||
|
||||
|
||||
return extractedRules
|
||||
return False
|
||||
|
||||
|
||||
# Combine test
|
||||
def parse_flodata(string):
|
||||
|
||||
if string[0:5] == 'text:':
|
||||
string = string.split('text:')[1]
|
||||
|
||||
cleanstring = re.sub(' +', ' ', string)
|
||||
cleanstring = cleanstring.lower()
|
||||
nospacestring = re.sub(' +', ' ', string)
|
||||
cleanstring = nospacestring.lower()
|
||||
|
||||
|
||||
if isTransfer(cleanstring):
|
||||
if isSmartContract(cleanstring):
|
||||
contractname = isSmartContract(cleanstring)
|
||||
marker = extractMarker(cleanstring)
|
||||
operation = extractOperation(cleanstring)
|
||||
amount = extractAmount(cleanstring)
|
||||
contractcondition = extractContractCondition(cleanstring)
|
||||
parsed_data = { 'type': 'transfer', 'transferType': 'smartContract', 'flodata': string, 'tokenIdentification': marker[:-1],
|
||||
'operation': operation, 'tokenAmount': amount, 'contractName': contractname, 'contractCondition': contractcondition}
|
||||
else:
|
||||
marker = extractMarker(cleanstring)
|
||||
operation = extractOperation(cleanstring)
|
||||
amount = extractAmount(cleanstring)
|
||||
address = extractAddress(nospacestring)
|
||||
parsed_data = {'type': 'transfer', 'transferType': 'token', 'flodata': string, 'tokenIdentification': marker[:-1], 'operation': operation,
|
||||
'amount': amount, 'address': address}
|
||||
|
||||
elif isSmartContractPay(nospacestring):
|
||||
contractConditions = isSmartContractPay(nospacestring)
|
||||
parsed_data = {'type': 'smartContractPays', 'flodata': string, 'smartContractTrigger':contractConditions['smartContractTrigger'], 'smartContractName':contractConditions['smartContractName']}
|
||||
|
||||
elif isSmartContract(cleanstring):
|
||||
contractname = isSmartContract(cleanstring)
|
||||
marker = extractMarker(cleanstring)
|
||||
operation = extractOperation(cleanstring)
|
||||
amount = extractAmount(cleanstring)
|
||||
parsed_data = {'type': 'transfer', 'flodata': string, 'marker': marker, 'operation': operation,
|
||||
'amount': amount}
|
||||
contracttype = extractContractType(cleanstring)
|
||||
contractaddress = extractAddress(nospacestring)
|
||||
contractconditions = extractContractConditions(cleanstring, 'betting*', marker)
|
||||
parsed_data = {'type': 'smartContractIncorporation', 'contractType': contracttype[:-1], 'tokenIdentification': marker[:-1], 'contractName': contractname[:-1], 'contractAddress':contractaddress[:-1], 'flodata': string, 'contractConditions': contractconditions}
|
||||
|
||||
elif isIncorp(cleanstring):
|
||||
incMarker = extractMarker(cleanstring)
|
||||
initTokens = extractInitTokens(cleanstring)
|
||||
parsed_data = {'type': 'incorporation', 'flodata': string, 'marker': incMarker, 'initTokens': initTokens}
|
||||
parsed_data = {'type': 'tokenIncorporation', 'flodata': string, 'tokenIdentification': incMarker[:-1], 'tokenAmount': initTokens}
|
||||
|
||||
else:
|
||||
parsed_data = {'type': 'noise'}
|
||||
|
||||
return parsed_data
|
||||
|
||||
return parsed_data
|
||||
result = parse_flodata('create electionbetting@ at address oM4pCYsbT5xg7bqLNCTXmoADUs6zBwLfXi$ of type betting* using the token rmt# with contractconditions: 1. userAssetCommitment="1rmt" 2. smartContractPays="NAMO=WIN | NAMO=LOOSE 3. expirydate=1553040000"')
|
||||
print(result)
|
||||
Binary file not shown.
Binary file not shown.
@ -8,7 +8,7 @@ import sys
|
||||
import parsing
|
||||
from sqlalchemy.orm import sessionmaker, relationship
|
||||
from sqlalchemy import create_engine, func, desc
|
||||
from models import Extra, TransactionHistory, TransactionTable, TransferLogs, Webtable, Base
|
||||
from models import Extra, TransactionHistory, TransactionTable, TransferLogs, Webtable, Base, ContractStructure
|
||||
|
||||
|
||||
def startWorking(transaction_data, parsed_data):
|
||||
@ -74,9 +74,27 @@ def startWorking(transaction_data, parsed_data):
|
||||
print("This transaction will be discarded")
|
||||
continue
|
||||
|
||||
# Check if the transaction is of the type 'incorporation'
|
||||
if parsed_data['type'] == 'incorporation':
|
||||
# Check if the transaction is of the type 'incorporation' or 'smartcontract'
|
||||
if parsed_data['type'] == 'smartcontract':
|
||||
print("I JUST FOUND THE INCORPORATION OF SMART CONTRACT \n" + str(parsed_data))
|
||||
if parsed_data['contracttype'] == 'betting*':
|
||||
print("Smart contract is of the type betting")
|
||||
if parsed_data['contractname'] is not None and parsed_data['contractaddress'][:-1] == outputlist[0][0]:
|
||||
print("Hey I have passed the first test for smart contract")
|
||||
#check if a db with contractname exists
|
||||
scengine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractname'][:-1]), echo=True)
|
||||
Base.metadata.create_all(bind=scengine)
|
||||
scsession = sessionmaker(bind=scengine)()
|
||||
scsession.add(ContractStructure(attribute='contracttype', index=0, value=parsed_data['contracttype'][:-1]))
|
||||
scsession.add(ContractStructure(attribute='contractname', index=0, value=parsed_data['contractname'][:-1]))
|
||||
scsession.add(
|
||||
ContractStructure(attribute='marker', index=0, value=parsed_data['marker'][:-1]))
|
||||
|
||||
scsession.commit()
|
||||
scsession.close()
|
||||
|
||||
sys.exit(0)
|
||||
elif parsed_data['type'] == 'incorporation':
|
||||
session.add(TransactionTable(address=outputlist[0][0], parentid=0, transferBalance=parsed_data['initTokens']))
|
||||
session.commit()
|
||||
#transferDescription = "Root address = " + str(root_address) + " has been initialized with " + str(root_init_value) + " tokens"
|
||||
@ -93,8 +111,7 @@ def startWorking(transaction_data, parsed_data):
|
||||
print("The input address dosen't exist in our database ")
|
||||
|
||||
elif availableTokens < commentTransferAmount:
|
||||
print(
|
||||
"\nThe transfer amount passed in the comments is more than the user owns\nThis transaction will be discarded\n")
|
||||
print("\nThe transfer amount passed in the comments is more than the user owns\nThis transaction will be discarded\n")
|
||||
continue
|
||||
|
||||
elif availableTokens >= commentTransferAmount:
|
||||
@ -216,6 +233,8 @@ def startWorking(transaction_data, parsed_data):
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
|
||||
|
||||
# Read configuration
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
@ -255,6 +274,7 @@ response = subprocess.check_output(string, shell=True)
|
||||
current_index = json.loads(response.decode("utf-8"))
|
||||
print("current_block_height : " + str(current_index))
|
||||
|
||||
|
||||
for blockindex in range( startblock, current_index ):
|
||||
print(blockindex)
|
||||
|
||||
@ -279,5 +299,4 @@ for blockindex in range( startblock, current_index ):
|
||||
if parsed_data['type'] != 'noise':
|
||||
print(blockindex)
|
||||
print(parsed_data['type'])
|
||||
startWorking(transaction_data, parsed_data)
|
||||
|
||||
startWorking(transaction_data, parsed_data)
|
||||
198
tracktokens-smartcontract.py
Normal file
198
tracktokens-smartcontract.py
Normal file
@ -0,0 +1,198 @@
|
||||
import requests
|
||||
import json
|
||||
import sqlite3
|
||||
import argparse
|
||||
import configparser
|
||||
import subprocess
|
||||
import sys
|
||||
import parsing
|
||||
import os
|
||||
import shutil
|
||||
from sqlalchemy.orm import sessionmaker, relationship
|
||||
from sqlalchemy import create_engine, func, desc
|
||||
from models import Extra, TransactionHistory, TransactionTable, TransferLogs, Webtable, Base, ContractStructure, ContractBase
|
||||
|
||||
|
||||
def startWorking(transaction_data, parsed_data):
|
||||
|
||||
# Do the necessary checks for the inputs and outputs
|
||||
|
||||
# Create inputlist and outputlist
|
||||
inputlist = []
|
||||
querylist = []
|
||||
|
||||
for obj in transaction_data["vin"]:
|
||||
querylist.append([obj["txid"], obj["vout"]])
|
||||
|
||||
if len(querylist) > 1:
|
||||
print("Program has detected more than one input address ")
|
||||
print("This transaction will be discarded")
|
||||
return
|
||||
|
||||
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(transaction_data["vout"]) > 2:
|
||||
print("Program has detected more than one output address ")
|
||||
print("This transaction will be discarded")
|
||||
return
|
||||
|
||||
outputlist = []
|
||||
for obj in transaction_data["vout"]:
|
||||
if obj["scriptPubKey"]["type"] == "pubkeyhash":
|
||||
if inputlist[0][0] == obj["scriptPubKey"]["addresses"][0]:
|
||||
continue
|
||||
|
||||
outputlist.append([obj["scriptPubKey"]["addresses"][0], obj["value"]])
|
||||
|
||||
print("\n\nInput List")
|
||||
print(inputlist)
|
||||
print("\nOutput List")
|
||||
print(outputlist)
|
||||
|
||||
|
||||
# Do operations as per the type of transaction
|
||||
if parsed_data['type'] == 'transfer':
|
||||
print('Found a transaction of the type transfer')
|
||||
|
||||
if parsed_data['transferType'] == 'smartContract':
|
||||
print('do something')
|
||||
|
||||
elif parsed_data['transferType'] == 'token':
|
||||
engine = create_engine('sqlite:///tokens/{}.db'.format(parsed_data['tokenIdentification']), echo=True)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
session = sessionmaker(bind=engine)()
|
||||
availableTokens = session.query(func.sum(TransactionTable.transferBalance)).filter_by(address=inputlist[0][0]).all()[0][0]
|
||||
commentTransferAmount = parsed_data['amount']
|
||||
if availableTokens is None:
|
||||
print("The input address dosen't exist in our database ")
|
||||
|
||||
elif availableTokens < commentTransferAmount:
|
||||
print(
|
||||
"\nThe transfer amount passed in the comments is more than the user owns\nThis transaction will be discarded\n")
|
||||
return
|
||||
|
||||
elif availableTokens >= commentTransferAmount:
|
||||
print("well i've reached here")
|
||||
|
||||
elif parsed_data['type'] == 'tokenIncorporation':
|
||||
if not os.path.isfile('./tokens/{}.db'.format(parsed_data['tokenIdentification'])):
|
||||
engine = create_engine('sqlite:///tokens/{}.db'.format(parsed_data['tokenIdentification']), echo=True)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
session = sessionmaker(bind=engine)()
|
||||
session.add(TransactionTable(address=outputlist[0][0], parentid=0, transferBalance=parsed_data['tokenAmount']))
|
||||
session.commit()
|
||||
session.close()
|
||||
else:
|
||||
print('Transaction rejected as the token with same name has already been incorporated')
|
||||
|
||||
elif parsed_data['type'] == 'smartContractIncorporation':
|
||||
if not os.path.isfile('./smartContracts/{}.db'.format(parsed_data['contractName'])):
|
||||
if parsed_data['contractType'] == 'betting':
|
||||
print("Smart contract is of the type betting")
|
||||
if parsed_data['contractName'] is not None and parsed_data['contractAddress'] == outputlist[0][0]:
|
||||
print("Hey I have passed the first test for smart contract")
|
||||
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True)
|
||||
ContractBase.metadata.create_all(bind=engine)
|
||||
session = sessionmaker(bind=engine)()
|
||||
session.add(ContractStructure(attribute='contractType', index=0, value=parsed_data['contractType']))
|
||||
session.add(ContractStructure(attribute='contractName', index=0, value=parsed_data['contractName']))
|
||||
session.add(
|
||||
ContractStructure(attribute='tokenIdentification', index=0, value=parsed_data['tokenIdentification']))
|
||||
session.add(
|
||||
ContractStructure(attribute='contractAddress', index=0, value=parsed_data['contractAddress'][:-1]))
|
||||
session.add(
|
||||
ContractStructure(attribute='flodata', index=0,
|
||||
value=parsed_data['flodata']))
|
||||
session.add(
|
||||
ContractStructure(attribute='userassetcommitment', index=0,
|
||||
value=parsed_data['contractConditions']['userassetcommitment'].split(parsed_data['tokenIdentification'][:-1])[0]))
|
||||
for key, value in parsed_data['contractConditions']['smartcontractpays'].items():
|
||||
session.add(ContractStructure(attribute='exitconditions', index=key, value=value))
|
||||
session.commit()
|
||||
session.close()
|
||||
else:
|
||||
print('Transaction rejected as a smartcontract with same name has already been incorporated')
|
||||
elif parsed_data['type'] == 'smartContractPays':
|
||||
print('Found a transaction of the type smartContractPays')
|
||||
|
||||
|
||||
|
||||
|
||||
# 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()
|
||||
|
||||
# Assignment the flo-cli command
|
||||
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\nThe script will exit now ")
|
||||
|
||||
|
||||
# Delete database and smartcontract directory if reset is set to 1
|
||||
if args.reset == 1:
|
||||
apppath = os.path.dirname(os.path.realpath(__file__))
|
||||
dirpath = os.path.join(apppath, 'tokens')
|
||||
shutil.rmtree(dirpath)
|
||||
os.mkdir(dirpath)
|
||||
dirpath = os.path.join(apppath, 'smartContracts')
|
||||
shutil.rmtree(dirpath)
|
||||
os.mkdir(dirpath)
|
||||
|
||||
|
||||
# Read start block no
|
||||
startblock = int(config['DEFAULT']['START_BLOCK'])
|
||||
|
||||
# Find 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))
|
||||
|
||||
|
||||
for blockindex in range( startblock, current_index ):
|
||||
print(blockindex)
|
||||
|
||||
# Scan every block
|
||||
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"))
|
||||
|
||||
# Scan every transaction
|
||||
for transaction in blockinfo["tx"]:
|
||||
string = "{} getrawtransaction {} 1".format(localapi, str(transaction))
|
||||
response = subprocess.check_output(string, shell=True)
|
||||
transaction_data = json.loads(response.decode("utf-8"))
|
||||
text = transaction_data["floData"]
|
||||
|
||||
parsed_data = parsing.parse_flodata(text)
|
||||
if parsed_data['type'] != 'noise':
|
||||
print(blockindex)
|
||||
print(parsed_data['type'])
|
||||
startWorking(transaction_data, parsed_data)
|
||||
Loading…
Reference in New Issue
Block a user