Smart contract integration - Half Done

This commit is contained in:
Vivek Teega 2019-03-18 14:44:24 +05:30
parent 38a00c9f2e
commit 11a4aa09c6
11 changed files with 351 additions and 22 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
tree.db
.idea/
flo_addresses.txt
__pycache__/
*.swp

Binary file not shown.

Binary file not shown.

View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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)

View 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)