Fix token tx repeatability problem and contract participation logic when no maximum specified amount

This commit is contained in:
Vivek Teega 2019-05-20 13:38:14 +05:30
parent 6f95ad889e
commit bb04439733
2 changed files with 87 additions and 41 deletions

View File

@ -186,18 +186,17 @@ def extractContractConditions(text, contracttype, marker, blocktime):
if rule == '': if rule == '':
continue continue
elif rule[:10] == 'expirytime': elif rule[:10] == 'expirytime':
pattern = re.compile('[^expirytime\s*=\s*].*') expirytime = re.split('expirytime[\s]*=[\s]*', rule)[1].strip()
expirytime = pattern.search(rule).group(0).strip()
try: try:
expirytime_split = expirytime.split(' ') expirytime_split = expirytime.split(' ')
parse_string = '{}/{}/{} {}'.format(expirytime_split[3], parsing.months[expirytime_split[1]], expirytime_split[2], expirytime_split[4]) parse_string = '{}/{}/{} {}'.format(expirytime_split[3], 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]) expirytime_object = arrow.get(parse_string, 'YYYY/M/D HH:mm:ss').replace(tzinfo=expirytime_split[5])
blocktime_object = arrow.get(blocktime) blocktime_object = arrow.get(blocktime)
if expirytime_object < blocktime_object: if expirytime_object < blocktime_object:
print('Expirytime of the contract is earlier than the block it is incorporated in. This incorporation will be rejected ') print('Expirytime of the contract is earlier than the block it is incorporated in. This incorporation will be rejected ')
return None return None
extractedRules['expirytime'] = expirytime extractedRules['expiryTime'] = expirytime
except: except:
print('Expiry time not in right format') print('Expiry time not in right format')
return None return None
@ -210,7 +209,7 @@ def extractContractConditions(text, contracttype, marker, blocktime):
searchResult = pattern.search(rule).group(0) searchResult = pattern.search(rule).group(0)
contractamount = searchResult.split(marker)[0] contractamount = searchResult.split(marker)[0]
try: try:
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':
@ -243,7 +242,7 @@ def extractContractConditions(text, contracttype, marker, blocktime):
extractedRules['payeeAddress'] = payeeAddress extractedRules['payeeAddress'] = payeeAddress
if len(extractedRules)>1 and 'expirytime' in extractedRules: if len(extractedRules)>1 and 'expiryTime' in extractedRules:
return extractedRules return extractedRules
else: else:
return None return None
@ -348,11 +347,14 @@ def parse_flodata(string, blockinfo):
# We are at the send/transfer of smart contract # We are at the send/transfer of smart contract
amount = extractAmount(cleanstring, hashList[0][:-1]) amount = extractAmount(cleanstring, hashList[0][:-1])
userChoice = extractUserchoice(cleanstring) userChoice = extractUserchoice(cleanstring)
contractaddress = extractAddress(nospacestring)
if None not in [amount, userChoice]: if None not in [amount, userChoice]:
parsed_data = {'type': 'transfer', 'transferType': 'smartContract', 'flodata': string, parsed_data = {'type': 'transfer', 'transferType': 'smartContract', 'flodata': string,
'tokenIdentification': hashList[0][:-1], 'tokenIdentification': hashList[0][:-1],
'operation': 'transfer', 'tokenAmount': amount, 'contractName': atList[0][:-1], 'operation': 'transfer', 'tokenAmount': amount, 'contractName': atList[0][:-1],
'userChoice': userChoice} 'userChoice': userChoice}
if contractaddress:
parsed_data['contractAddress'] = contractaddress[:-1]
else: else:
parsed_data = {'type': 'noise'} parsed_data = {'type': 'noise'}

View File

@ -155,7 +155,7 @@ def transferToken(tokenIdentification, tokenAmount, inputAddress, outputAddress)
def checkLocaltriggerContracts(blockinfo): def checkLocaltriggerContracts(blockinfo):
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect() connection = engine.connect()
# todo : filter activeContracts which only have local triggers # todo : filter activeContracts which only have local triggers
activeContracts = connection.execute('select contractName, contractAddress from activecontracts where status=="active" ').fetchall() activeContracts = connection.execute('select contractName, contractAddress from activecontracts where status=="active" ').fetchall()
@ -163,11 +163,11 @@ def checkLocaltriggerContracts(blockinfo):
for contract in activeContracts: for contract in activeContracts:
# Check if the contract has blockchain trigger or committee trigger # Check if the contract has blockchain trigger or committee trigger
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(contract[0],contract[1]), echo=True) engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(contract[0],contract[1]), echo=False)
connection = engine.connect() connection = engine.connect()
# todo : filter activeContracts which only have local triggers # todo : filter activeContracts which only have local triggers
contractStructure = connection.execute('select * from contractstructure').fetchall() contractStructure = connection.execute('select * from contractstructure').fetchall()
contractStructure_T = list(zip(*contractstructure)) contractStructure_T = list(zip(*contractStructure))
if 'exitconditions' in list(contractStructure_T[1]): if 'exitconditions' in list(contractStructure_T[1]):
# This is a committee trigger contract # This is a committee trigger contract
@ -214,7 +214,7 @@ def checkLocaltriggerContracts(blockinfo):
if returnval is None: if returnval is None:
print("Something went wrong in the token transfer method while doing local Smart Contract Trigger") print("Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return return
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect() connection = engine.connect()
connection.execute( connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format( 'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
@ -249,7 +249,7 @@ def checkLocaltriggerContracts(blockinfo):
print( print(
"Something went wrong in the token transfer method while doing local Smart Contract Trigger") "Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return return
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect() connection = engine.connect()
connection.execute( connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format( 'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
@ -264,7 +264,7 @@ def checkLocaltriggerContracts(blockinfo):
if returnval is None: if returnval is None:
print("Something went wrong in the token transfer method while doing local Smart Contract Trigger") print("Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return return
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect() connection = engine.connect()
connection.execute( connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format( 'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
@ -355,19 +355,37 @@ def startWorking(transaction_data, parsed_data, blockinfo):
# All FLO checks completed at this point. # All FLO checks completed at this point.
# Semantic rules for parsed data begins # Semantic rules for parsed data begins
# todo Rule 44 - Process as per the type of transaction # todo Rule 44 - Process as per the type of transaction
if parsed_data['type'] == 'transfer': if parsed_data['type'] == 'transfer':
print('Found a transaction of the type transfer') print('Found a transaction of the type transfer')
# todo Rule 45 - If the transfer type is token, then call the function transferToken to adjust the balances # todo Rule 45 - If the transfer type is token, then call the function transferToken to adjust the balances
if parsed_data['transferType'] == 'token': if parsed_data['transferType'] == 'token':
# Check if the transaction hash already exists in the token db
engine = create_engine('sqlite:///tokens/{}.db'.format(parsed_data['tokenIdentification']), echo=True)
connection = engine.connect()
blockno_txhash = connection.execute('select blockNumber, transactionHash from transactionHistory').fetchall()
blockno_txhash_T = list(zip(*blockno_txhash))
if transaction_data['txid'] in blockno_txhash_T:
print('Transaction already exists in the db. This is unusual, please check your code')
return
returnval = transferToken(parsed_data['tokenIdentification'], parsed_data['tokenAmount'], inputlist[0], outputlist[0]) returnval = transferToken(parsed_data['tokenIdentification'], parsed_data['tokenAmount'], inputlist[0], outputlist[0])
if returnval is None: if returnval is None:
print("Something went wrong in the token transfer method") print("Something went wrong in the token transfer method")
# 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':
#if contractAddress was passed check if it matches the output address of this contract
if 'contractAddress' in parsed_data:
if parsed_data['contractAddress'] != outputlist[0]:
print('Mismatch in contract address specified in flodata and the output address of the transaction')
print('This contract transfer will be rejected')
return
# check if the contract is active # check if the contract is active
engine = create_engine('sqlite:///system.db', echo=True) engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect() connection = engine.connect()
@ -390,6 +408,7 @@ def startWorking(transaction_data, parsed_data, blockinfo):
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()
session.close()
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()
@ -401,16 +420,19 @@ def startWorking(transaction_data, parsed_data, blockinfo):
if blocktime_object > expirytime_object: if blocktime_object > expirytime_object:
print('Contract has expired and will not accept any user participation') print('Contract has expired and will not accept any user participation')
return return
session.close()
# Check if usercondition given is in right format if it exists as part of contractstructure # Check if exitcondition exists as part of contractstructure and is given in right format
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True) engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True)
connection = engine.connect() 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]): contractAttributes = connection.execute('select attribute, value from contractstructure').fetchall()
contractAttributes_T = list(zip(*contractAttributes))
if 'exitconditions' in contractAttributes_T[0]:
exitconditions = connection.execute('select id,value from contractstructure where attribute=="exitconditions"').fetchall()
exitconditions_T = list(zip(*exitconditions))
if parsed_data['userChoice'] not in list(exitconditions_T[1]):
print("Wrong userchoice entered\nThis smartContract pariticipation will be rejected") print("Wrong userchoice entered\nThis smartContract pariticipation will be rejected")
return return
@ -420,8 +442,8 @@ def startWorking(transaction_data, parsed_data, blockinfo):
contractAmount = connection.execute('select value from contractstructure where attribute=="contractAmount"').fetchall() contractAmount = connection.execute('select value from contractstructure where attribute=="contractAmount"').fetchall()
connection.close() connection.close()
if contractAmount is not None: if len(contractAmount) != 0:
if contractAmount[0][0] != parsed_data['tokenAmount']: if float(contractAmount[0][0]) != float(parsed_data['tokenAmount']):
print('Token amount being transferred is not part of the contract structure\nThis transaction will be discarded') print('Token amount being transferred is not part of the contract structure\nThis transaction will be discarded')
return return
@ -434,7 +456,6 @@ def startWorking(transaction_data, parsed_data, blockinfo):
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())
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]
if amountDeposited is None: if amountDeposited is None:
@ -460,9 +481,11 @@ def startWorking(transaction_data, parsed_data, blockinfo):
session.add(ContractParticipantMapping(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'], session.add(ContractParticipantMapping(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'],
contractName = parsed_data['contractName'], contractAddress = outputlist[0])) contractName = parsed_data['contractName'], contractAddress = outputlist[0]))
session.commit() session.commit()
return
else: else:
print("Something went wrong in the smartcontract token transfer method") print("Something went wrong in the smartcontract token transfer method")
return
else: else:
# Transfer only part of the tokens users specified, till the time it reaches maximumamount # Transfer only part of the tokens users specified, till the time it reaches maximumamount
returnval = transferToken(parsed_data['tokenIdentification'], maximumsubscriptionamount-amountDeposited, returnval = transferToken(parsed_data['tokenIdentification'], maximumsubscriptionamount-amountDeposited,
@ -484,12 +507,28 @@ def startWorking(transaction_data, parsed_data, blockinfo):
contractName=parsed_data['contractName'], contractAddress = outputlist[0])) contractName=parsed_data['contractName'], contractAddress = outputlist[0]))
session.commit() session.commit()
session.close() session.close()
return
else: else:
print("Something went wrong in the smartcontract token transfer method") print("Something went wrong in the smartcontract token transfer method")
return
# 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() 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()
return
# 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
@ -535,7 +574,7 @@ def startWorking(transaction_data, parsed_data, blockinfo):
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 # userchoice and payeeAddress conditions cannot come together. Check for it
if 'userchoice' in parsed_data['contractConditions'] and 'payeeAddress' in parsed_data['contractConditions']: if 'userchoices' 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'])) 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 return
@ -557,12 +596,12 @@ 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='expirytime', index=0, ContractStructure(attribute='expiryTime', index=0,
value=parsed_data['contractConditions']['expirytime'])) value=parsed_data['contractConditions']['expiryTime']))
if 'contractamount' in parsed_data['contractConditions']: if 'contractAmount' in parsed_data['contractConditions']:
session.add( session.add(
ContractStructure(attribute='contractamount', index=0, ContractStructure(attribute='contractAmount', index=0,
value=parsed_data['contractConditions']['contractamount'])) value=parsed_data['contractConditions']['contractAmount']))
if 'minimumsubscriptionamount' in parsed_data['contractConditions']: if 'minimumsubscriptionamount' in parsed_data['contractConditions']:
session.add( session.add(
@ -575,20 +614,25 @@ def startWorking(transaction_data, parsed_data, blockinfo):
if 'userchoices' in parsed_data['contractConditions']: if 'userchoices' in parsed_data['contractConditions']:
for key, value in parsed_data['contractConditions']['userchoices'].items(): for key, value in parsed_data['contractConditions']['userchoices'].items():
session.add(ContractStructure(attribute='exitconditions', index=key, value=value)) session.add(ContractStructure(attribute='exitconditions', index=key, value=value))
elif 'payeeAddress' in parsed_data['contractConditions']:
# in this case, expirydate( or maximumamount) is the trigger internally. Keep a track of expiry dates
session.add(
ContractStructure(attribute='payeeAddress', index=0,
value=parsed_data['contractConditions']['payeeAddress']))
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']))
return
session.commit()
session.close()
# Store smart contract address in system's db, to be ignored during future transfers # Store smart contract address in system's db, to be ignored during future transfers
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(ActiveContracts(contractName=parsed_data['contractName'],contractAddress=parsed_data['contractAddress'], status='active')) session.add(ActiveContracts(contractName=parsed_data['contractName'],
elif 'payeeAddress' in parsed_data['contractConditions']: contractAddress=parsed_data['contractAddress'], status='active'))
# 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']))
session.commit() session.commit()
session.close() session.close()
else: else:
@ -823,7 +867,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 == 593777: if blockindex == 606098:
print('hello') print('hello')
# Scan every block # Scan every block