Updating reject cases, checks for userchoice during participation, Blockchain triggers when committee triggers aren't required

This commit is contained in:
Vivek Teega 2019-05-20 09:27:12 +05:30
parent f0d852d96f
commit 6f95ad889e
3 changed files with 411 additions and 107 deletions

View File

@ -71,6 +71,7 @@ class ActiveContracts(SystemBase):
id = Column('id', Integer, primary_key=True) id = Column('id', Integer, primary_key=True)
contractName = Column('contractName', String) contractName = Column('contractName', String)
contractAddress = Column('contractAddress', String) contractAddress = Column('contractAddress', String)
status = Column('status', String)
class SystemData(SystemBase): class SystemData(SystemBase):
__tablename__ = "systemData" __tablename__ = "systemData"
@ -85,6 +86,7 @@ class ContractParticipantMapping(SystemBase):
id = Column('id', Integer, primary_key=True) id = Column('id', Integer, primary_key=True)
participantAddress = Column('participantAddress', String) participantAddress = Column('participantAddress', String)
contractName = Column('contractName', String) contractName = Column('contractName', String)
contractAddress = Column('contractAddress', String)
tokenAmount = Column('tokenAmount', Float) tokenAmount = Column('tokenAmount', Float)

View File

@ -6,6 +6,19 @@ operation = None
address = None address = None
amount = None amount = None
months = { 'jan' : 1,
'feb' : 2,
'mar' : 3,
'apr' : 4,
'may' : 5,
'jun' : 6,
'jul' : 7,
'aug' : 8,
'sep' : 9,
'oct' : 10,
'nov' : 11,
'dec' : 12 }
def isTransfer(text): def isTransfer(text):
wordlist = ['transfer','send','give'] # keep everything lowercase wordlist = ['transfer','send','give'] # keep everything lowercase
@ -145,7 +158,7 @@ def brackets_toNumber(item):
return float(item[1:-1]) return float(item[1:-1])
def extractContractConditions(text, contracttype, marker): def extractContractConditions(text, contracttype, marker, blocktime):
rulestext = re.split('contract-conditions:\s*', text)[-1] rulestext = re.split('contract-conditions:\s*', text)[-1]
#rulelist = re.split('\d\.\s*', rulestext) #rulelist = re.split('\d\.\s*', rulestext)
rulelist = [] rulelist = []
@ -168,10 +181,31 @@ def extractContractConditions(text, contracttype, marker):
if contracttype == 'one-time-event*': if contracttype == 'one-time-event*':
extractedRules = {} extractedRules = {}
for rule in rulelist:
if rule == '':
continue
elif rule[:10] == 'expirytime':
pattern = re.compile('[^expirytime\s*=\s*].*')
expirytime = pattern.search(rule).group(0).strip()
try:
expirytime_split = expirytime.split(' ')
parse_string = '{}/{}/{} {}'.format(expirytime_split[3], parsing.months[expirytime_split[1]], expirytime_split[2], expirytime_split[4])
expirytime_object = arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(tzinfo=expirytime_split[5])
blocktime_object = arrow.get(blocktime)
if expirytime_object < blocktime_object:
print('Expirytime of the contract is earlier than the block it is incorporated in. This incorporation will be rejected ')
return None
extractedRules['expirytime'] = expirytime
except:
print('Expiry time not in right format')
return None
for rule in rulelist: for rule in rulelist:
if rule=='': if rule=='':
continue continue
elif rule[:14]=='contractamount': elif rule[:14] == 'contractamount':
pattern = re.compile('[^contractamount\s*=\s*].*') pattern = re.compile('[^contractamount\s*=\s*].*')
searchResult = pattern.search(rule).group(0) searchResult = pattern.search(rule).group(0)
contractamount = searchResult.split(marker)[0] contractamount = searchResult.split(marker)[0]
@ -179,20 +213,13 @@ def extractContractConditions(text, contracttype, marker):
extractedRules['contractamount'] = float(contractamount) extractedRules['contractamount'] = float(contractamount)
except: except:
print("something is wrong with contract amount entered") print("something is wrong with contract amount entered")
elif rule[:11]=='userchoices': elif rule[:11] == 'userchoices':
pattern = re.compile('[^userchoices\s*=\s*].*') pattern = re.compile('[^userchoices\s*=\s*].*')
conditions = pattern.search(rule).group(0) conditions = pattern.search(rule).group(0)
conditionlist = conditions.split('|') conditionlist = conditions.split('|')
extractedRules['userchoices'] = {} extractedRules['userchoices'] = {}
for idx, condition in enumerate(conditionlist): for idx, condition in enumerate(conditionlist):
extractedRules['userchoices'][idx] = condition.strip() extractedRules['userchoices'][idx] = condition.strip()
elif rule[:10]=='expirytime':
pattern = re.compile('[^expirytime\s*=\s*].*')
searchResult = pattern.search(rule).group(0).strip()
if searchResult == 'date-time':
continue
else:
extractedRules['expirytime'] = searchResult
elif rule[:25] == 'minimumsubscriptionamount': elif rule[:25] == 'minimumsubscriptionamount':
pattern = re.compile('[^minimumsubscriptionamount\s*=\s*].*') pattern = re.compile('[^minimumsubscriptionamount\s*=\s*].*')
searchResult = pattern.search(rule).group(0) searchResult = pattern.search(rule).group(0)
@ -209,9 +236,14 @@ def extractContractConditions(text, contracttype, marker):
extractedRules['maximumsubscriptionamount'] = float(maximumsubscriptionamount) extractedRules['maximumsubscriptionamount'] = float(maximumsubscriptionamount)
except: except:
print("something is wrong with maximum subscription amount entered") print("something is wrong with maximum subscription amount entered")
elif rule[:12] == 'payeeAddress':
pattern = re.compile('[^payeeAddress\s*=\s*].*')
searchResult = pattern.search(rule).group(0)
payeeAddress = searchResult.split(marker)[0]
extractedRules['payeeAddress'] = payeeAddress
if 'contractamount' in extractedRules and 'userchoices' in extractedRules: if len(extractedRules)>1 and 'expirytime' in extractedRules:
return extractedRules return extractedRules
else: else:
return None return None
@ -227,7 +259,7 @@ def extractTriggerCondition(text):
# Combine test # Combine test
def parse_flodata(string): def parse_flodata(string, blockinfo):
# todo Rule 20 - remove 'text:' from the start of flodata if it exists # todo Rule 20 - remove 'text:' from the start of flodata if it exists
if string[0:5] == 'text:': if string[0:5] == 'text:':
@ -301,7 +333,7 @@ def parse_flodata(string):
elif incorporation and not transfer: elif incorporation and not transfer:
contracttype = extractContractType(cleanstring) contracttype = extractContractType(cleanstring)
contractaddress = extractAddress(nospacestring) contractaddress = extractAddress(nospacestring)
contractconditions = extractContractConditions(cleanstring, 'one-time-event*', marker=hashList[0][:-1]) contractconditions = extractContractConditions(cleanstring, contracttype, marker=hashList[0][:-1], blocktime=blockinfo['time'])
if None not in [contracttype, contractaddress, contractconditions]: if None not in [contracttype, contractaddress, contractconditions]:
parsed_data = {'type': 'smartContractIncorporation', 'contractType': contracttype[:-1], parsed_data = {'type': 'smartContractIncorporation', 'contractType': contracttype[:-1],
@ -326,7 +358,7 @@ def parse_flodata(string):
# todo Rule 36 - Check for only a single @ and the substring "smart contract system says" in flodata, else reject # todo Rule 36 - Check for only a single @ and the substring "smart contract system says" in flodata, else reject
elif (len(hashList)==0 and len(atList)==1) and 'smart contract system says' in cleanstring: elif (len(hashList)==0 and len(atList)==1):
# Passing the above check means Smart Contract pays | exitcondition triggered from the committee # Passing the above check means Smart Contract pays | exitcondition triggered from the committee
# todo Rule 37 - Extract the trigger condition given by the committee. If its missing, reject # todo Rule 37 - Extract the trigger condition given by the committee. If its missing, reject
triggerCondition = extractTriggerCondition(cleanstring) triggerCondition = extractTriggerCondition(cleanstring)

View File

@ -14,22 +14,9 @@ from sqlalchemy import create_engine, func, desc
from models import SystemData, ActiveTable, ConsumedTable, TransferLogs, TransactionHistory, Base, ContractStructure, ContractBase, ContractParticipants, SystemBase, ActiveContracts, ContractParticipantMapping from models import SystemData, ActiveTable, ConsumedTable, TransferLogs, TransactionHistory, Base, ContractStructure, ContractBase, ContractParticipants, SystemBase, ActiveContracts, ContractParticipantMapping
months = { 'jan' : 1,
'feb' : 2,
'mar' : 3,
'apr' : 4,
'may' : 5,
'jun' : 6,
'jul' : 7,
'aug' : 8,
'sep' : 9,
'oct' : 10,
'nov' : 11,
'dec' : 12 }
committeeAddressList = ['oUc4dVvxwK7w5MHUHtev8UawN3eDjiZnNx'] committeeAddressList = ['oUc4dVvxwK7w5MHUHtev8UawN3eDjiZnNx']
def transferToken(tokenIdentification, tokenAmount, inputAddress, outputAddress): def transferToken(tokenIdentification, tokenAmount, inputAddress, outputAddress):
engine = create_engine('sqlite:///tokens/{}.db'.format(tokenIdentification), echo=True) engine = create_engine('sqlite:///tokens/{}.db'.format(tokenIdentification), echo=True)
Base.metadata.create_all(bind=engine) Base.metadata.create_all(bind=engine)
@ -167,6 +154,125 @@ def transferToken(tokenIdentification, tokenAmount, inputAddress, outputAddress)
return 1 return 1
def checkLocaltriggerContracts(blockinfo):
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
# todo : filter activeContracts which only have local triggers
activeContracts = connection.execute('select contractName, contractAddress from activecontracts where status=="active" ').fetchall()
connection.close()
for contract in activeContracts:
# Check if the contract has blockchain trigger or committee trigger
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(contract[0],contract[1]), echo=True)
connection = engine.connect()
# todo : filter activeContracts which only have local triggers
contractStructure = connection.execute('select * from contractstructure').fetchall()
contractStructure_T = list(zip(*contractstructure))
if 'exitconditions' in list(contractStructure_T[1]):
# This is a committee trigger contract
expiryTime = connection.execute('select value from contractstructure where attribute=="expiryTime"').fetchall()[0][0]
expirytime_split = expiryTime.split(' ')
parse_string = '{}/{}/{} {}'.format(expirytime_split[3], parsing.months[expirytime_split[1]],
expirytime_split[2], expirytime_split[4])
expirytime_object = parsing.arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(
tzinfo=expirytime_split[5])
blocktime_object = parsing.arrow.get(blockinfo['time'])
if blocktime_object > expirytime_object:
if 'minimumsubscriptionamount' in list(contractStructure_T[1]):
minimumsubscriptionamount = connection.execute('select value from contractstructure where attribute=="minimumsubscriptionamount"').fetchall()[0][0]
tokenAmount_sum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0]
if tokenAmount_sum < minimumsubscriptionamount:
# Initialize payback to contract participants
contractParticipants = connection.execute('select participantAddress, tokenAmount from contractparticipants').fetchall()[0][0]
for participant in contractParticipants:
tokenIdentification = connection.execute('select * from contractstructure where attribute="tokenIdentification"').fetchall()[0][0]
contractAddress = connection.execute('select * from contractstructure where attribute="contractAddress"').fetchall()[0][0]
returnval = transferToken(tokenIdentification, participant[1], contractAddress, participant[0])
if returnval is None:
print("Something went wrong in the token transfer method while doing local Smart Contract Trigger")
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(contract[0], contract[1]))
connection.close()
else:
# This is a blockchain trigger contract
if 'maximumsubscriptionamount' in list(contractStructure_T[1]):
maximumsubscriptionamount = connection.execute('select value from contractstructure where attribute=="maximumsubscriptionamount"').fetchall()[0][0]
tokenAmount_sum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0]
if tokenAmount_sum >= maximumsubscriptionamount:
# Trigger the contract
payeeAddress = connection.execute('select * from contractstructure where attribute="payeeAddress"').fetchall()[0][0]
tokenIdentification = connection.execute('select * from contractstructure where attribute="tokenIdentification"').fetchall()[0][0]
contractAddress = connection.execute('select * from contractstructure where attribute="contractAddress"').fetchall()[0][0]
returnval = transferToken(tokenIdentification, tokenAmount_sum, contractAddress, payeeAddress)
if returnval is None:
print("Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
contract[0], contract[1]))
connection.close()
expiryTime = connection.execute('select value from contractstructure where attribute=="expiryTime"').fetchall()[0][0]
expirytime_split = expiryTime.split(' ')
parse_string = '{}/{}/{} {}'.format(expirytime_split[3], parsing.months[expirytime_split[1]], expirytime_split[2], expirytime_split[4])
expirytime_object = parsing.arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(
tzinfo=expirytime_split[5])
blocktime_object = parsing.arrow.get(blockinfo['time'])
if blocktime_object > expirytime_object:
if 'minimumsubscriptionamount' in list(contractStructure_T[1]):
minimumsubscriptionamount = connection.execute('select value from contractstructure where attribute=="minimumsubscriptionamount"').fetchall()[0][0]
tokenAmount_sum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0]
if tokenAmount_sum < minimumsubscriptionamount:
# Initialize payback to contract participants
contractParticipants = connection.execute(
'select participantAddress, tokenAmount from contractparticipants').fetchall()[0][0]
for participant in contractParticipants:
tokenIdentification = connection.execute(
'select * from contractstructure where attribute="tokenIdentification"').fetchall()[0][
0]
contractAddress = connection.execute(
'select * from contractstructure where attribute="contractAddress"').fetchall()[0][0]
returnval = transferToken(tokenIdentification, participant[1], contractAddress,
participant[0])
if returnval is None:
print(
"Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
contract[0], contract[1]))
connection.close()
# Trigger the contract
payeeAddress = connection.execute('select * from contractstructure where attribute="payeeAddress"').fetchall()[0][0]
tokenIdentification = connection.execute('select * from contractstructure where attribute="tokenIdentification"').fetchall()[0][0]
contractAddress = connection.execute('select * from contractstructure where attribute="contractAddress"').fetchall()[0][0]
returnval = transferToken(tokenIdentification, tokenAmount_sum, contractAddress, payeeAddress)
if returnval is None:
print("Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
contract[0], contract[1]))
connection.close()
def startWorking(transaction_data, parsed_data, blockinfo): def startWorking(transaction_data, parsed_data, blockinfo):
# Do the necessary checks for the inputs and outputs # Do the necessary checks for the inputs and outputs
@ -262,24 +368,33 @@ def startWorking(transaction_data, parsed_data, blockinfo):
# todo Rule 46 - If the transfer type is smart contract, then call the function transferToken to do sanity checks & lock the balance # todo Rule 46 - If the transfer type is smart contract, then call the function transferToken to do sanity checks & lock the balance
elif parsed_data['transferType'] == 'smartContract': elif parsed_data['transferType'] == 'smartContract':
# check if the contract is active
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
contractDetails = connection.execute(
'select contractName, contractAddress from activecontracts where status=="active"').fetchall()
connection.close()
contractList = []
#Check if the db exists counter = 0
apppath = os.path.dirname(os.path.realpath(__file__)) for contract in contractDetails:
dirpath = os.path.join(apppath, 'smartContracts','{}.db'.format(parsed_data['contractName'])) if contract[0] == parsed_data['contractName'] and contract[1] == outputlist[0]:
if not os.path.exists(dirpath): counter = counter + 1
print('Smart contract with the given name doesn\'t exist')
if counter != 1:
print('Active Smart contract with the given name doesn\'t exist')
return return
# Check if the contract has expired # Check if the contract has expired
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
ContractBase.metadata.create_all(bind=engine) ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
result = session.query(ContractStructure).filter_by(attribute='expirytime').all() result = session.query(ContractStructure).filter_by(attribute='expiryTime').all()
if result: if result:
#now parse the expiry time in python #now parse the expiry time in python
expirytime = result[0].value.strip() expirytime = result[0].value.strip()
expirytime_split = expirytime.split(' ') expirytime_split = expirytime.split(' ')
parse_string = '{}/{}/{} {}'.format( expirytime_split[3], months[expirytime_split[1]], expirytime_split[2], expirytime_split[4]) parse_string = '{}/{}/{} {}'.format( expirytime_split[3], parsing.months[expirytime_split[1]], expirytime_split[2], expirytime_split[4])
expirytime_object = parsing.arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(tzinfo=expirytime_split[5]) expirytime_object = parsing.arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(tzinfo=expirytime_split[5])
blocktime_object = parsing.arrow.get(blockinfo['time']) blocktime_object = parsing.arrow.get(blockinfo['time'])
@ -289,53 +404,92 @@ def startWorking(transaction_data, parsed_data, blockinfo):
session.close() session.close()
# Check if usercondition given is in right format if it exists as part of contractstructure
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
connection = engine.connect()
activeContracts = connection.execute('select value from contractstructure where attribute=="exitconditions"').fetchall()
connection.close()
if parsed_data['userChoice'] is not in list(activeContracts[0]):
print("Wrong userchoice entered\nThis smartContract pariticipation will be rejected")
return
# Check if contractAmount is part of the contract structure, and enforce it if it is
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
connection = engine.connect()
contractAmount = connection.execute('select value from contractstructure where attribute=="contractAmount"').fetchall()
connection.close()
if contractAmount is not None:
if contractAmount[0][0] != parsed_data['tokenAmount']:
print('Token amount being transferred is not part of the contract structure\nThis transaction will be discarded')
return
# Check if maximum subscription amount has reached # Check if maximum subscription amount has reached
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
ContractBase.metadata.create_all(bind=engine) ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
result = session.query(ContractStructure).filter_by(attribute='maximumsubscriptionamount').all() result = session.query(ContractStructure).filter_by(attribute='maximumsubscriptionamount').all()
session.close()
if result: if result:
# now parse the expiry time in python # now parse the expiry time in python
maximumsubscriptionamount = float(result[0].value.strip()) maximumsubscriptionamount = float(result[0].value.strip())
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True)
ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
result = session.query(ContractStructure).filter_by(attribute='maximumsubscriptionamount').all() result = session.query(ContractStructure).filter_by(attribute='maximumsubscriptionamount').all()
amountDeposited = session.query(func.sum(ContractParticipants.tokenAmount)).all()[0][0] amountDeposited = session.query(func.sum(ContractParticipants.tokenAmount)).all()[0][0]
session.close()
if amountDeposited is None: if amountDeposited is None:
amountDeposited = 0 amountDeposited = 0
if amountDeposited >= maximumsubscriptionamount: if amountDeposited >= maximumsubscriptionamount:
print('Maximum subscription amount reached') print('Maximum subscription amount reached\n Money will be refunded')
return return
else:
if parsed_data['tokenAmount']+amountDeposited <= maximumsubscriptionamount:
# Check if the tokenAmount being transferred exists in the address & do the token transfer
returnval = transferToken(parsed_data['tokenIdentification'], parsed_data['tokenAmount'], inputlist[0], outputlist[0])
if returnval is not None:
# Store participant details in the smart contract's db
session.add(ContractParticipants(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'], userChoice=parsed_data['userChoice']))
session.commit()
session.close()
# Store a mapping of participant address -> Contract participated in
engine = create_engine('sqlite:///system.db', echo=True)
SystemBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
session.add(ContractParticipantMapping(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'],
contractName = parsed_data['contractName'], contractAddress = outputlist[0]))
session.commit()
# Check if the tokenAmount being transferred exists in the address & do the token transfer else:
returnval = transferToken(parsed_data['tokenIdentification'], parsed_data['tokenAmount'], inputlist[0], outputlist[0]) print("Something went wrong in the smartcontract token transfer method")
if returnval is not None: else:
# Store participant details in the smart contract's db # Transfer only part of the tokens users specified, till the time it reaches maximumamount
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) returnval = transferToken(parsed_data['tokenIdentification'], maximumsubscriptionamount-amountDeposited,
ContractBase.metadata.create_all(bind=engine) inputlist[0], outputlist[0])
session = sessionmaker(bind=engine)() if returnval is not None:
session.add(ContractParticipants(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'], userChoice=parsed_data['userChoice'])) # Store participant details in the smart contract's db
session.commit() session.add(ContractParticipants(participantAddress=inputadd,
session.close() tokenAmount=maximumsubscriptionamount-amountDeposited,
userChoice=parsed_data['userChoice']))
session.commit()
session.close()
# Store a mapping of participant address -> Contract participated in # Store a mapping of participant address -> Contract participated in
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=True)
SystemBase.metadata.create_all(bind=engine) SystemBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
session.add(ContractParticipantMapping(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'], session.add(ContractParticipantMapping(participantAddress=inputadd,
contractName = parsed_data['contractName'])) tokenAmount=maximumsubscriptionamount-amountDeposited,
session.commit() contractName=parsed_data['contractName'], contractAddress = outputlist[0]))
session.close() session.commit()
session.close()
else:
print("Something went wrong in the smartcontract token transfer method")
session.close()
else:
print("Something went wrong in the smartcontract token transfer method")
# todo Rule 47 - If the parsed data type is token incorporation, then check if the name hasn't been taken already # todo Rule 47 - If the parsed data type is token incorporation, then check if the name hasn't been taken already
# if it has been taken then reject the incorporation. Else incorporate it # if it has been taken then reject the incorporation. Else incorporate it
@ -363,16 +517,34 @@ def startWorking(transaction_data, parsed_data, blockinfo):
# todo Rule 48 - If the parsed data type if smart contract incorporation, then check if the name hasn't been taken already # todo Rule 48 - If the parsed data type if smart contract incorporation, then check if the name hasn't been taken already
# if it has been taken then reject the incorporation. # if it has been taken then reject the incorporation.
elif parsed_data['type'] == 'smartContractIncorporation': elif parsed_data['type'] == 'smartContractIncorporation':
if not os.path.isfile('./smartContracts/{}.db'.format(parsed_data['contractName'])): engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
contractDetails = connection.execute('select contractName, contractAddress from activecontracts').fetchall()
connection.close()
counter = 0
# Check if the combination of contract name and address exists
for contract in contractDetails:
if contract[0] == parsed_data['contractName'] and contract[1] == parsed_data['contractAddress']:
counter = counter + 1
if counter == 0:
# todo Rule 49 - If the contract name hasn't been taken before, check if the contract type is an authorized type by the system # todo Rule 49 - If the contract name hasn't been taken before, check if the contract type is an authorized type by the system
if parsed_data['contractType'] == 'one-time-event': if parsed_data['contractType'] == 'one-time-event':
print("Smart contract is of the type one-time-event") print("Smart contract is of the type one-time-event")
# userchoice and payeeAddress conditions cannot come together. Check for it
if 'userchoice' in parsed_data['contractConditions'] and 'payeeAddress' in parsed_data['contractConditions']:
print('Both userchoice and payeeAddress provided as part of the Contract conditions\nIncorporation of Smart Contract with the name {} will be rejected'.format(parsed_data['contractName']))
return
# todo Rule 50 - Contract address mentioned in flodata field should be same as the receiver FLO address on the output side # todo Rule 50 - Contract address mentioned in flodata field should be same as the receiver FLO address on the output side
# henceforth we will not consider any flo private key initiated comment as valid from this address # henceforth we will not consider any flo private key initiated comment as valid from this address
# Unlocking can only be done through smart contract system address # Unlocking can only be done through smart contract system address
if parsed_data['contractAddress'] == inputadd: if parsed_data['contractAddress'] == inputadd:
print("Hey I have passed the first test for smart contract") dbName = '{}-{}'.format(parsed_data['contractName'], parsed_data['contractAddress'])
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) engine = create_engine('sqlite:///smartContracts/{}.db'.format(dbName), echo=True)
ContractBase.metadata.create_all(bind=engine) ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
session.add(ContractStructure(attribute='contractType', index=0, value=parsed_data['contractType'])) session.add(ContractStructure(attribute='contractType', index=0, value=parsed_data['contractType']))
@ -385,12 +557,13 @@ def startWorking(transaction_data, parsed_data, blockinfo):
ContractStructure(attribute='flodata', index=0, ContractStructure(attribute='flodata', index=0,
value=parsed_data['flodata'])) value=parsed_data['flodata']))
session.add( session.add(
ContractStructure(attribute='contractamount', index=0,
value=parsed_data['contractConditions']['contractamount']))
if 'expirytime' in parsed_data['contractConditions']:
session.add(
ContractStructure(attribute='expirytime', index=0, ContractStructure(attribute='expirytime', index=0,
value=parsed_data['contractConditions']['expirytime'])) value=parsed_data['contractConditions']['expirytime']))
if 'contractamount' in parsed_data['contractConditions']:
session.add(
ContractStructure(attribute='contractamount', index=0,
value=parsed_data['contractConditions']['contractamount']))
if 'minimumsubscriptionamount' in parsed_data['contractConditions']: if 'minimumsubscriptionamount' in parsed_data['contractConditions']:
session.add( session.add(
ContractStructure(attribute='minimumsubscriptionamount', index=0, ContractStructure(attribute='minimumsubscriptionamount', index=0,
@ -399,49 +572,112 @@ def startWorking(transaction_data, parsed_data, blockinfo):
session.add( session.add(
ContractStructure(attribute='maximumsubscriptionamount', index=0, ContractStructure(attribute='maximumsubscriptionamount', index=0,
value=parsed_data['contractConditions']['maximumsubscriptionamount'])) value=parsed_data['contractConditions']['maximumsubscriptionamount']))
for key, value in parsed_data['contractConditions']['userchoices'].items(): if 'userchoices' in parsed_data['contractConditions']:
session.add(ContractStructure(attribute='exitconditions', index=key, value=value)) for key, value in parsed_data['contractConditions']['userchoices'].items():
session.commit() session.add(ContractStructure(attribute='exitconditions', index=key, value=value))
session.close() # Store smart contract address in system's db, to be ignored during future transfers
engine = create_engine('sqlite:///system.db', echo=True)
SystemBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
session.add(ActiveContracts(contractName=parsed_data['contractName'],contractAddress=parsed_data['contractAddress'], status='active'))
elif 'payeeAddress' in parsed_data['contractConditions']:
# in this case, expirydate( or maximumamount) is the trigger internally. Keep a track of expiry dates
engine = create_engine('sqlite:///system.db', echo=True)
SystemBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
session.add(ActiveContracts(contractName=parsed_data['contractName'], contractAddress=parsed_data['contractAddress'], expiryTime=parsed_data['contractConditions']['expirytime'], maximumSubscription=parsed_data['contractConditions']['maximumsubscriptionamount'], status='active'))
else:
print('Neither userchoice nor payeeAddress provided as part of Smart Contract incorporation of the name {}\n This contract incorporation will be rejected'.format(parsed_data['contractName']))
# Store smart contract address in system's db, to be ignored during future transfers
engine = create_engine('sqlite:///system.db',
echo=True)
SystemBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
session.add(
ActiveContracts(contractName=parsed_data['contractName'], contractAddress=parsed_data['contractAddress']))
session.commit() session.commit()
session.close() session.close()
else:
print('Contract Incorporation rejected as address in Flodata and input address are different')
else: else:
print('Transaction rejected as a smartcontract with same name has already been incorporated') print('Transaction rejected as a smartcontract with same name is active currently')
elif parsed_data['type'] == 'smartContractPays': elif parsed_data['type'] == 'smartContractPays':
print('Found a transaction of the type smartContractPays') print('Found a transaction of the type smartContractPays')
# Check if input address is a committee address # Check if input address is a committee address
if inputlist[0] in committeeAddressList: if inputlist[0] in committeeAddressList:
# Check if the output address is an active Smart contract address # Check if the output address is an active Smart contract address
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect() connection = engine.connect()
activeContracts = connection.execute('select * from activecontracts').fetchall() # todo : Get only activeContracts which have non-local trigger ie. committee triggers them
contractDetails = connection.execute('select contractName, contractAddress from activecontracts where status=="active"').fetchall()
connection.close()
contractList = []
counter = 0
for contract in contractDetails:
if contract[0] == parsed_data['contractName'] and contract[1] == outputlist[0]:
counter = counter + 1
if counter != 1:
print('Active Smart contract with the given name doesn\'t exist\n This committee trigger will be rejected')
return
# Check if the contract has maximumsubscriptionamount and if it has reached it
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
connection = engine.connect()
# todo : filter activeContracts which only have local triggers
contractStructure = connection.execute('select * from contractstructure').fetchall()
contractStructure_T = list(zip(*contractstructure))
if 'maximumsubscriptionamount' in list(contractStructure_T[1]):
maximumsubscriptionamount = connection.execute('select value from contractstructure where attribute=="maximumsubscriptionamount"').fetchall()[0][0]
tokenAmount_sum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0]
if tokenAmount_sum >= maximumsubscriptionamount:
# Trigger the contract
contractWinners = connection.execute(
'select * from contractparticipants where userChoice="{}"'.format(
parsed_data['triggerCondition'])).fetchall()
tokenSum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0]
winnerSum = connection.execute(
'select sum(tokenAmount) from contractparticipants where userChoice="{}"'.format(
parsed_data['triggerCondition'])).fetchall()
tokenIdentification = connection.execute(
'select value from contractstructure where attribute="tokenIdentification"').fetchall()[0][0]
connection.close()
for winner in contractWinners:
returnval = transferToken(tokenIdentification, (winner[2] / winnerSum) * tokenSum,
outputlist[0], winner[1])
if returnval is None:
print("CRITICAL ERROR | Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(parsed_data['contractName'], outputlist[0]))
connection.close()
return
# Check if contract has passed expiry time
expiryTime = connection.execute('select value from contractstructure where attibute=="expiryTime"').fetchall()[0][0]
expirytime_split = expiryTime.split(' ')
parse_string = '{}/{}/{} {}'.format(expirytime_split[3], parsing.months[expirytime_split[1]],
expirytime_split[2], expirytime_split[4])
expirytime_object = parsing.arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(
tzinfo=expirytime_split[5])
blocktime_object = parsing.arrow.get(blockinfo['time'])
connection.close() connection.close()
# Change columns into rows - https://stackoverflow.com/questions/44360162/how-to-access-a-column-in-a-list-of-lists-in-python if blocktime_object > expirytime_object:
activeContracts = list(zip(*activeContracts))
if outputlist[0] in activeContracts[2] and parsed_data['contractName'] in activeContracts[1]:
# Check if the minimum subscription amount has been reached if it exists as part of the structure # Check if the minimum subscription amount has been reached if it exists as part of the structure
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
ContractBase.metadata.create_all(bind=engine) ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
result = session.query(ContractStructure).filter_by(attribute='minimumsubscriptionamount').all() result = session.query(ContractStructure).filter_by(attribute='minimumsubscriptionamount').all()
session.close() session.close()
if result: if result:
# now parse the expiry time in python
minimumsubscriptionamount = float(result[0].value.strip()) minimumsubscriptionamount = float(result[0].value.strip())
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]),
echo=True) echo=True)
ContractBase.metadata.create_all(bind=engine) ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)() session = sessionmaker(bind=engine)()
@ -453,33 +689,64 @@ def startWorking(transaction_data, parsed_data, blockinfo):
amountDeposited = 0 amountDeposited = 0
if amountDeposited < minimumsubscriptionamount: if amountDeposited < minimumsubscriptionamount:
print('Minimum subscription amount reached') print('Minimum subscription amount hasn\'t been reached\n The token will be returned back')
# Initialize payback to contract participants
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]),
echo=True)
connection = engine.connect()
contractParticipants = connection.execute(
'select participantAddress, tokenAmount from contractparticipants').fetchall()[0][0]
for participant in contractParticipants:
tokenIdentification = connection.execute(
'select * from contractstructure where attribute="tokenIdentification"').fetchall()[0][
0]
contractAddress = connection.execute(
'select * from contractstructure where attribute="contractAddress"').fetchall()[0][0]
returnval = transferToken(tokenIdentification, participant[1], contractAddress,
participant[0])
if returnval is None:
print(
"CRITICAL ERROR | Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
parsed_data['contractName'], outputlist[0]))
connection.close()
return return
engine = create_engine('sqlite:///smartContracts/{}.db'.format(parsed_data['contractName']), echo=True) engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
connection = engine.connect() connection = engine.connect()
contractWinners = connection.execute('select * from contractparticipants where userChoice="{}"'.format(parsed_data['triggerCondition'])).fetchall() contractWinners = connection.execute('select * from contractparticipants where userChoice="{}"'.format(parsed_data['triggerCondition'])).fetchall()
tokenSum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0] tokenSum = connection.execute('select sum(tokenAmount) from contractparticipants').fetchall()[0][0]
winnerSum = connection.execute('select sum(tokenAmount) from contractparticipants where userChoice="{}"'.format(parsed_data['triggerCondition'])).fetchall()
tokenIdentification = connection.execute('select value from contractstructure where attribute="tokenIdentification"').fetchall()[0][0] tokenIdentification = connection.execute('select value from contractstructure where attribute="tokenIdentification"').fetchall()[0][0]
connection.close() connection.close()
contractWinners = list(zip(*contractWinners)) for winner in contractWinners:
for address in contractWinners[1]: returnval = transferToken(tokenIdentification, (winner[2]/winnerSum)*tokenSum, outputlist[0], winner[1])
transferToken(tokenIdentification, tokenSum/len(contractWinners[1]), outputlist[0], address) if returnval is None:
print(
else: "CRITICAL ERROR | Something went wrong in the token transfer method while doing local Smart Contract Trigger")
print('This trigger doesn\'t apply to an active contract. It will be discarded') return
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
parsed_data['contractName'], outputlist[0]))
connection.close()
else: else:
print('Input address is not part of the committee address list. This trigger is rejected') print('Input address is not part of the committee address list. This trigger is rejected')
# todo Rule 1 - Read command line arguments to reset the databases as blank
# Rule 2 - Read config to set testnet/mainnet
# Rule 3 - Set flo blockexplorer location depending on testnet or mainnet
# Rule 4 - Set the local flo-cli path depending on testnet or mainnet
# Rule 5 - Set the block number to scan from
# todo Rule 1 - Read command line arguments to reset the databases as blank
# Rule 2 - Read config to set testnet/mainnet
# Rule 3 - Set flo blockexplorer location depending on testnet or mainnet
# Rule 4 - Set the local flo-cli path depending on testnet or mainnet
# Rule 5 - Set the block number to scan from
# Read command line arguments # Read command line arguments
@ -556,7 +823,7 @@ print("current_block_height : " + str(current_index))
for blockindex in range( startblock, current_index ): for blockindex in range( startblock, current_index ):
print(blockindex) print(blockindex)
if blockindex == 590795: if blockindex == 593777:
print('hello') print('hello')
# Scan every block # Scan every block
@ -580,7 +847,7 @@ for blockindex in range( startblock, current_index ):
# todo Rule 9 - Reject all noise transactions. Further rules are in parsing.py # todo Rule 9 - Reject all noise transactions. Further rules are in parsing.py
parsed_data = parsing.parse_flodata(text) parsed_data = parsing.parse_flodata(text, blockinfo)
if parsed_data['type'] != 'noise': if parsed_data['type'] != 'noise':
print(blockindex) print(blockindex)
print(parsed_data['type']) print(parsed_data['type'])
@ -594,3 +861,6 @@ for blockindex in range( startblock, current_index ):
session.commit() session.commit()
session.close() session.close()
# Check smartContracts which will be triggered locally, and not by the contract committee
checkLocaltriggerContracts(blockinfo)