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 == '':
continue
elif rule[:10] == 'expirytime':
pattern = re.compile('[^expirytime\s*=\s*].*')
expirytime = pattern.search(rule).group(0).strip()
expirytime = re.split('expirytime[\s]*=[\s]*', rule)[1].strip()
try:
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])
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
extractedRules['expiryTime'] = expirytime
except:
print('Expiry time not in right format')
return None
@ -210,7 +209,7 @@ def extractContractConditions(text, contracttype, marker, blocktime):
searchResult = pattern.search(rule).group(0)
contractamount = searchResult.split(marker)[0]
try:
extractedRules['contractamount'] = float(contractamount)
extractedRules['contractAmount'] = float(contractamount)
except:
print("something is wrong with contract amount entered")
elif rule[:11] == 'userchoices':
@ -243,7 +242,7 @@ def extractContractConditions(text, contracttype, marker, blocktime):
extractedRules['payeeAddress'] = payeeAddress
if len(extractedRules)>1 and 'expirytime' in extractedRules:
if len(extractedRules)>1 and 'expiryTime' in extractedRules:
return extractedRules
else:
return None
@ -348,11 +347,14 @@ def parse_flodata(string, blockinfo):
# We are at the send/transfer of smart contract
amount = extractAmount(cleanstring, hashList[0][:-1])
userChoice = extractUserchoice(cleanstring)
contractaddress = extractAddress(nospacestring)
if None not in [amount, userChoice]:
parsed_data = {'type': 'transfer', 'transferType': 'smartContract', 'flodata': string,
'tokenIdentification': hashList[0][:-1],
'operation': 'transfer', 'tokenAmount': amount, 'contractName': atList[0][:-1],
'userChoice': userChoice}
if contractaddress:
parsed_data['contractAddress'] = contractaddress[:-1]
else:
parsed_data = {'type': 'noise'}

View File

@ -155,7 +155,7 @@ def transferToken(tokenIdentification, tokenAmount, inputAddress, outputAddress)
def checkLocaltriggerContracts(blockinfo):
engine = create_engine('sqlite:///system.db', echo=True)
engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect()
# todo : filter activeContracts which only have local triggers
activeContracts = connection.execute('select contractName, contractAddress from activecontracts where status=="active" ').fetchall()
@ -163,11 +163,11 @@ def checkLocaltriggerContracts(blockinfo):
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)
engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(contract[0],contract[1]), echo=False)
connection = engine.connect()
# todo : filter activeContracts which only have local triggers
contractStructure = connection.execute('select * from contractstructure').fetchall()
contractStructure_T = list(zip(*contractstructure))
contractStructure_T = list(zip(*contractStructure))
if 'exitconditions' in list(contractStructure_T[1]):
# This is a committee trigger contract
@ -214,7 +214,7 @@ def checkLocaltriggerContracts(blockinfo):
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)
engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
@ -249,7 +249,7 @@ def checkLocaltriggerContracts(blockinfo):
print(
"Something went wrong in the token transfer method while doing local Smart Contract Trigger")
return
engine = create_engine('sqlite:///system.db', echo=True)
engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect()
connection.execute(
'update activecontracts set status="closed" where contractName="{}" and contractAddress="{}"'.format(
@ -264,7 +264,7 @@ def checkLocaltriggerContracts(blockinfo):
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)
engine = create_engine('sqlite:///system.db', echo=False)
connection = engine.connect()
connection.execute(
'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.
# Semantic rules for parsed data begins
# todo Rule 44 - Process as per the type of transaction
if parsed_data['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
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])
if returnval is None:
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
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
engine = create_engine('sqlite:///system.db', echo=True)
connection = engine.connect()
@ -390,6 +408,7 @@ def startWorking(transaction_data, parsed_data, blockinfo):
ContractBase.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
result = session.query(ContractStructure).filter_by(attribute='expiryTime').all()
session.close()
if result:
#now parse the expiry time in python
expirytime = result[0].value.strip()
@ -401,18 +420,21 @@ def startWorking(transaction_data, parsed_data, blockinfo):
if blocktime_object > expirytime_object:
print('Contract has expired and will not accept any user participation')
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)
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
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")
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)
@ -420,8 +442,8 @@ def startWorking(transaction_data, parsed_data, blockinfo):
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']:
if len(contractAmount) != 0:
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')
return
@ -434,7 +456,6 @@ def startWorking(transaction_data, parsed_data, blockinfo):
if result:
# now parse the expiry time in python
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]
if amountDeposited is None:
@ -444,7 +465,7 @@ def startWorking(transaction_data, parsed_data, blockinfo):
print('Maximum subscription amount reached\n Money will be refunded')
return
else:
if parsed_data['tokenAmount']+amountDeposited <= maximumsubscriptionamount:
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:
@ -460,9 +481,11 @@ def startWorking(transaction_data, parsed_data, blockinfo):
session.add(ContractParticipantMapping(participantAddress=inputadd, tokenAmount=parsed_data['tokenAmount'],
contractName = parsed_data['contractName'], contractAddress = outputlist[0]))
session.commit()
return
else:
print("Something went wrong in the smartcontract token transfer method")
return
else:
# Transfer only part of the tokens users specified, till the time it reaches maximumamount
returnval = transferToken(parsed_data['tokenIdentification'], maximumsubscriptionamount-amountDeposited,
@ -484,14 +507,30 @@ def startWorking(transaction_data, parsed_data, blockinfo):
contractName=parsed_data['contractName'], contractAddress = outputlist[0]))
session.commit()
session.close()
return
else:
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()
# 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
elif parsed_data['type'] == 'tokenIncorporation':
if not os.path.isfile('./tokens/{}.db'.format(parsed_data['tokenIdentification'])):
@ -535,7 +574,7 @@ def startWorking(transaction_data, parsed_data, blockinfo):
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']:
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']))
return
@ -557,12 +596,12 @@ def startWorking(transaction_data, parsed_data, blockinfo):
ContractStructure(attribute='flodata', index=0,
value=parsed_data['flodata']))
session.add(
ContractStructure(attribute='expirytime', index=0,
value=parsed_data['contractConditions']['expirytime']))
if 'contractamount' in parsed_data['contractConditions']:
ContractStructure(attribute='expiryTime', index=0,
value=parsed_data['contractConditions']['expiryTime']))
if 'contractAmount' in parsed_data['contractConditions']:
session.add(
ContractStructure(attribute='contractamount', index=0,
value=parsed_data['contractConditions']['contractamount']))
ContractStructure(attribute='contractAmount', index=0,
value=parsed_data['contractConditions']['contractAmount']))
if 'minimumsubscriptionamount' in parsed_data['contractConditions']:
session.add(
@ -575,22 +614,27 @@ def startWorking(transaction_data, parsed_data, blockinfo):
if 'userchoices' in parsed_data['contractConditions']:
for key, value in parsed_data['contractConditions']['userchoices'].items():
session.add(ContractStructure(attribute='exitconditions', index=key, value=value))
# 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'))
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
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'))
session.commit()
session.close()
else:
print('Contract Incorporation rejected as address in Flodata and input address are different')
@ -823,7 +867,7 @@ print("current_block_height : " + str(current_index))
for blockindex in range( startblock, current_index ):
print(blockindex)
if blockindex == 593777:
if blockindex == 606098:
print('hello')
# Scan every block