diff --git a/app.py b/app.py index 9b76661..4a292ef 100644 --- a/app.py +++ b/app.py @@ -4,7 +4,6 @@ from flask import Flask, jsonify app = Flask(__name__) - @app.route('/') def hello_world(): return 'Hello, World!' @@ -20,4 +19,4 @@ def marker_list(): return jsonify(dbdict) -app.run(debug=True) +app.run(debug=True) \ No newline at end of file diff --git a/models.py b/models.py index ca07bb1..7f6ee7d 100644 --- a/models.py +++ b/models.py @@ -5,6 +5,7 @@ Base = declarative_base() ContractBase = declarative_base() SystemBase = declarative_base() LatestCacheBase = declarative_base() +ContinuosContractBase = declarative_base() class ActiveTable(Base): @@ -222,3 +223,55 @@ class LatestBlocks(LatestCacheBase): blockNumber = Column('blockNumber', String) blockHash = Column('blockHash', String) jsonData = Column('jsonData', String) + + +class ContractStructure1(ContinuosContractBase): + __tablename__ = "contractstructure" + + id = Column('id', Integer, primary_key=True) + attribute = Column('attribute', String) + index = Column('index', Integer) + value = Column('value', String) + + +class ContractParticipants1(ContinuosContractBase): + __tablename__ = "contractparticipants" + + id = Column('id', Integer, primary_key=True) + participantAddress = Column('participantAddress', String) + tokenAmount = Column('tokenAmount', Float) + userChoice = Column('userChoice', String) + transactionHash = Column('transactionHash', String) + blockNumber = Column('blockNumber', Integer) + blockHash = Column('blockHash', String) + winningAmount = Column('winningAmount', Float) + + +class ContractDeposits1(ContinuosContractBase): + __tablename__ = "contractdeposits" + + id = Column('id', Integer, primary_key=True) + depositorAddress = Column('depositorAddress', String) + depositAmount = Column('depositAmount', Float) + expiryTime = Column('expiryTime', String) + transactionHash = Column('transactionHash', String) + blockNumber = Column('blockNumber', Integer) + blockHash = Column('blockHash', String) + + +class ContractTransactionHistory1(ContinuosContractBase): + __tablename__ = "contractTransactionHistory" + + primary_key = Column('id', Integer, primary_key=True) + transactionType = Column('transactionType', String) + transactionSubType = Column('transactionSubType', String) + sourceFloAddress = Column('sourceFloAddress', String) + destFloAddress = Column('destFloAddress', String) + transferAmount = Column('transferAmount', Float) + blockNumber = Column('blockNumber', Integer) + blockHash = Column('blockHash', String) + time = Column('time', Integer) + transactionHash = Column('transactionHash', String) + blockchainReference = Column('blockchainReference', String) + jsonData = Column('jsonData', String) + parsedFloData = Column('parsedFloData', String) \ No newline at end of file diff --git a/parsing.py b/parsing.py index e0fe046..5e0d883 100644 --- a/parsing.py +++ b/parsing.py @@ -1,7 +1,7 @@ -import configparser import re - import arrow +import pdb +import configparser config = configparser.ConfigParser() config.read('config.ini') @@ -11,18 +11,20 @@ operation = None address = 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} +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): @@ -34,6 +36,15 @@ def isTransfer(text): return False +def isDeposit(text): + wordlist = ['submit', 'deposit'] # keep everything lowercase + textList = text.split(' ') + for word in wordlist: + if word in textList: + return True + return False + + def isIncorp(text): wordlist = ['incorporate', 'create', 'start'] # keep everything lowercase textList = text.split(' ') @@ -63,7 +74,8 @@ def isSmartContractPay(text): smartContractName = smartContractName[:-1] if smartContractTrigger and smartContractName: - contractconditions = {'smartContractTrigger': smartContractTrigger, 'smartContractName': smartContractName} + contractconditions = { + 'smartContractTrigger': smartContractTrigger, 'smartContractName': smartContractName} return contractconditions else: return False @@ -88,6 +100,26 @@ def extractAmount(text, marker): return returnval +def extractSubmitAmount(text, marker): + count = 0 + returnval = None + text = text.split('deposit-conditions')[0] + splitText = text.split(' ') + + for word in splitText: + word = word.replace(marker, '') + try: + float(word) + count = count + 1 + returnval = float(word) + except ValueError: + continue + + if count > 1: + return 'Too many' + return returnval + + def extractMarker(text): textList = text.split(' ') for word in textList: @@ -139,7 +171,8 @@ def extractAddress(text): def extractContractType(text): - operationList = ['one-time-event*'] # keep everything lowercase + # keep everything lowercase + operationList = ['one-time-event*', 'continuous-event*'] count = 0 returnval = None for operation in operationList: @@ -163,7 +196,7 @@ def brackets_toNumber(item): return float(item[1:-1]) -def extractContractConditions(text, contracttype, marker, blocktime): +def extractContractConditions(text, contracttype, blocktime, marker=None): rulestext = re.split('contract-conditions:\s*', text)[-1] # rulelist = re.split('\d\.\s*', rulestext) rulelist = [] @@ -181,12 +214,12 @@ def extractContractConditions(text, contracttype, marker, blocktime): break for i in range(len(numberList)): - rule = rulestext.split('({})'.format(i + 1))[1].split('({})'.format(i + 2))[0] + rule = rulestext.split('({})'.format( + i + 1))[1].split('({})'.format(i + 2))[0] rulelist.append(rule.strip()) if contracttype == 'one-time-event*': extractedRules = {} - for rule in rulelist: if rule == '': continue @@ -195,9 +228,10 @@ def extractContractConditions(text, contracttype, marker, blocktime): try: expirytime_split = expirytime.split(' ') - 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]) + 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( @@ -231,7 +265,8 @@ def extractContractConditions(text, contracttype, marker, blocktime): searchResult = pattern.search(rule).group(0) minimumsubscriptionamount = searchResult.split(marker)[0] try: - extractedRules['minimumsubscriptionamount'] = float(minimumsubscriptionamount) + extractedRules['minimumsubscriptionamount'] = float( + minimumsubscriptionamount) except: print("Minimum subscription amount entered is not a decimal") elif rule[:25] == 'maximumsubscriptionamount': @@ -239,7 +274,8 @@ def extractContractConditions(text, contracttype, marker, blocktime): searchResult = pattern.search(rule).group(0) maximumsubscriptionamount = searchResult.split(marker)[0] try: - extractedRules['maximumsubscriptionamount'] = float(maximumsubscriptionamount) + extractedRules['maximumsubscriptionamount'] = float( + maximumsubscriptionamount) except: print("Maximum subscription amount entered is not a decimal") elif rule[:12] == 'payeeaddress': @@ -252,9 +288,114 @@ def extractContractConditions(text, contracttype, marker, blocktime): return extractedRules else: return None + + elif contracttype == 'continuous-event*': + extractedRules = {} + for rule in rulelist: + print(rule) + if rule == '': + continue + elif rule[:7] == 'subtype': + # todo : recheck the regular expression for subtype, find an elegant version which covers all permutations and combinations + '''pattern = re.compile('[^subtype\s*=].*') + searchResult = pattern.search(rule).group(0) + subtype = searchResult.split(marker)[0]''' + extractedRules['subtype'] = rule.split('=')[1].strip() + elif rule[:15] == 'accepting_token': + pattern = re.compile('[^accepting_token\s*=\s*].*') + searchResult = pattern.search(rule).group(0) + accepting_token = searchResult.split(marker)[0] + extractedRules['accepting_token'] = accepting_token + elif rule[:13] == 'selling_token': + pattern = re.compile('[^selling_token\s*=\s*].*') + searchResult = pattern.search(rule).group(0) + selling_token = searchResult.split(marker)[0] + extractedRules['selling_token'] = selling_token + elif rule[:9].lower() == 'pricetype': + pattern = re.compile('[^pricetype\s*=\s*].*') + searchResult = pattern.search(rule).group(0) + priceType = searchResult.split(marker)[0] + extractedRules['priceType'] = priceType + elif rule[:5] == 'price': + pattern = re.compile('[^price\s*=\s*].*') + searchResult = pattern.search(rule).group(0) + price = searchResult.split(marker)[0] + if price[0]=="'" or price[0]=='"': + price = price[1:] + if price[-1]=="'" or price[-1]=='"': + price = price[:-1] + extractedRules['price'] = float(price) + # else: + # pdb.set_trace() + if len(extractedRules) > 1: + return extractedRules + else: + return None + return None +def extractDepositConditions(text, blocktime): + rulestext = re.split('deposit-conditions:\s*', text)[-1] + # rulelist = re.split('\d\.\s*', rulestext) + rulelist = [] + numberList = re.findall(r'\(\d\d*\)', rulestext) + for idx, item in enumerate(numberList): + numberList[idx] = int(item[1:-1]) + + numberList = sorted(numberList) + for idx, item in enumerate(numberList): + if len(numberList) > 1 and numberList[idx] + 1 != numberList[idx + 1]: + print('Deposit condition numbers are not in order') + return None + if idx == len(numberList) - 2: + break + + for i in range(len(numberList)): + rule = rulestext.split('({})'.format( + i + 1))[1].split('({})'.format(i + 2))[0] + rulelist.append(rule.strip()) + + # elif contracttype == 'continuous-event*': + extractedRules = {} + for rule in rulelist: + if rule == '': + continue + elif rule[:10] == 'expirytime': + expirytime = re.split('expirytime[\s]*=[\s]*', rule)[1].strip() + + try: + expirytime_split = expirytime.split(' ') + 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 + except: + print('Error parsing expiry time') + return None + + """for rule in rulelist: + if rule == '': + continue + elif rule[:7] == 'subtype': + subtype=rule[8:] + #pattern = re.compile('[^subtype\s*=\s*].*') + #searchResult = pattern.search(rule).group(0) + #contractamount = searchResult.split(marker)[0] + extractedRules['subtype'] = subtype """ + + if len(extractedRules) > 0: + return extractedRules + else: + return None + + def extractTriggerCondition(text): searchResult = re.search('\".*\"', text) if searchResult is None: @@ -265,40 +406,69 @@ def extractTriggerCondition(text): # Combine test def parse_flodata(string, blockinfo, netvariable): + + print("Break point at the first line of parsing function") # todo Rule 20 - remove 'text:' from the start of flodata if it exists if string[0:5] == 'text:': string = string.split('text:')[1] # todo Rule 21 - Collapse multiple spaces into a single space in the whole of flodata # todo Rule 22 - convert flodata to lowercase to make the system case insensitive - nospacestring = re.sub(' +', ' ', string) + nospacestring = re.sub('\t', ' ', string) + nospacestring = re.sub('\n', ' ', nospacestring) + nospacestring = re.sub(' +', ' ', nospacestring) cleanstring = nospacestring.lower() + #cleanstring_noconditions = cleanstring.split('contract-conditions:')[0] + cleanstring_split = re.compile("contract-conditions*[' ']:").split(cleanstring) # todo Rule 23 - Count number of words ending with @ and # atList = [] hashList = [] + starList = [] - for word in cleanstring.split(' '): + for word in cleanstring_split[0].split(' '): + if word.endswith('*') and len(word) != 1: + starList.append(word) + if word.endswith('@') and len(word) != 1: + atList.append(word) + + if len(starList) != 1 or starList[0] not in ['one-time-event*', 'continuous-event*']: + parsed_data = {'type': 'noise'} + else: + if starList == 'one-time-event*': + for word in cleanstring_split[0].split(' '): + if word.endswith('#') and len(word) != 1: + hashList.append(word) + elif starList == 'continuous-event*': + for word in cleanstring_split[1].split(' '): + if word.endswith('#') and len(word) != 1: + hashList.append(word) + + + '''for word in cleanstring_noconditions.split(' '): if word.endswith('@') and len(word) != 1: atList.append(word) if word.endswith('#') and len(word) != 1: hashList.append(word) + if word.endswith('*') and len(word) != 1: + starList.append(word) + ''' + print('') # todo Rule 24 - Reject the following conditions - a. number of # & number of @ is equal to 0 then reject # todo Rule 25 - If number of # or number of @ is greater than 1, reject # todo Rule 25.a - If a transaction is rejected, it means parsed_data type is noise # Filter noise first - check if the words end with either @ or # - if (len(atList) == 0 and len(hashList) == 0) or len(atList) > 1 or len(hashList) > 1: + if (len(atList) == 0 and len(hashList) == 0) or len(atList) > 1 or len(hashList) > 2 or len(starList) > 1: parsed_data = {'type': 'noise'} - # todo Rule 26 - if number of # is 1 and number of @ is 0, then check if its token creation or token transfer transaction - - elif len(hashList) == 1 and len(atList) == 0: + # todo Rule 26 - if number of # is 1 and numbner of @ is 0 and number of * is 0, then check if its token creation or token transfer transaction + elif len(hashList) == 1 and len(atList) == 0 and len(starList) == 0: # Passing the above check means token creation or transfer incorporation = isIncorp(cleanstring) transfer = isTransfer(cleanstring) - # todo Rule 27 - if (neither token incorporation and token transfer) OR both token incorporation and token transfer, reject + # todo Rule 27 - if (neither token incorporation a if (not incorporation and not transfer) or (incorporation and transfer): parsed_data = {'type': 'noise'} @@ -316,29 +486,35 @@ def parse_flodata(string, blockinfo, netvariable): # todo Rule 31 - Extract number of tokens to be sent and the address to which to be sent, both data is mandatory elif not incorporation and transfer: amount = extractAmount(cleanstring, hashList[0][:-1]) - if None not in [amount] and amount!='Too many': + if None not in [amount]: parsed_data = {'type': 'transfer', 'transferType': 'token', 'flodata': string, 'tokenIdentification': hashList[0][:-1], 'tokenAmount': amount} else: parsed_data = {'type': 'noise'} - # todo Rule 32 - if number of # is 1 and number of @ is 1, then process for smart contract transfer or creation - elif len(hashList) == 1 and len(atList) == 1: + # todo Rule 32 - if number of @ is 1, then process for smart contract transfer or creation or trigger + elif len(atList) == 1: # Passing the above check means Smart Contract creation or transfer incorporation = isIncorp(cleanstring) transfer = isTransfer(cleanstring) - + deposit = isDeposit(cleanstring) # todo Rule 33 - if a confusing smart contract command is given, like creating and sending at the same time, or no - if (not incorporation and not transfer) or (incorporation and transfer): + if incorporation and transfer: parsed_data = {'type': 'noise'} # todo Rule 34 - if incorporation and not transfer, then extract type of contract, address of the contract and conditions of the contract. Reject if any of those is not present elif incorporation and not transfer: contracttype = extractContractType(cleanstring) contractaddress = extractAddress(nospacestring) - contractconditions = extractContractConditions(cleanstring, contracttype, marker=hashList[0][:-1], - blocktime=blockinfo['time']) + + if contracttype == 'one-time-event*' and len(hashList) == 1: + contractconditions = extractContractConditions(cleanstring, contracttype, blocktime=blockinfo['time'], marker=hashList[0][:-1]) + elif contracttype == 'continuous-event*': + contractconditions = extractContractConditions(cleanstring, contracttype, blocktime=blockinfo['time']) + else: + parsed_data = {'type': 'noise'} + return parsed_data if config['DEFAULT']['NET'] == 'mainnet' and blockinfo['height'] < 3454510: if None not in [contracttype, contractconditions]: @@ -349,16 +525,29 @@ def parse_flodata(string, blockinfo, netvariable): else: parsed_data = {'type': 'noise'} else: - if None not in [contracttype, contractaddress, contractconditions]: + if None not in [contracttype, contractaddress, contractconditions] and contracttype[:-1] == 'one-time-event': parsed_data = {'type': 'smartContractIncorporation', 'contractType': contracttype[:-1], 'tokenIdentification': hashList[0][:-1], 'contractName': atList[0][:-1], 'contractAddress': contractaddress[:-1], 'flodata': string, 'contractConditions': contractconditions} + elif None not in [contracttype, contractaddress, contractconditions] and contracttype[:-1] == 'continuous-event': + if contractconditions['subtype'] == 'tokenswap' and ('priceType' not in contractconditions): + parsed_data = {'type': 'noise'} + return parsed_data + else: + parsed_data = {'type': 'smartContractIncorporation', 'contractType': contracttype[:-1], 'contractName': atList[0][:-1], + 'contractAddress': contractaddress[:-1], 'flodata': string, + 'contractConditions': contractconditions} else: parsed_data = {'type': 'noise'} # todo Rule 35 - if it is not incorporation and it is transfer, then extract smart contract amount to be locked and userPreference. If any of them is missing, then reject elif not incorporation and transfer: + # todo - Temporary check for transaction 22196cc761043b96a06fcfe5e58af2dafb90c7d222dcb909b537f7ee6715f0bd on testnet , figure out an elegant way of doing this + if len(hashList) == 0: + parsed_data = {'type': 'noise'} + return parsed_data + # We are at the send/transfer of smart contract amount = extractAmount(cleanstring, hashList[0][:-1]) userChoice = extractUserchoice(cleanstring) @@ -373,18 +562,34 @@ def parse_flodata(string, blockinfo, netvariable): else: parsed_data = {'type': 'noise'} + elif deposit: + # Figure out amount of token to be submitted + for word in cleanstring_split[0].split(' '): + if word.endswith('#') and len(word) != 1: + hashList.append(word) + depositAmount = extractSubmitAmount(cleanstring_split[0], hashList[0][:-1]) + # '' name of token = hashList[0] + # '' name of Smart Contract = atList[0] + # '' FLO address of the Smart Contract + # '' Submit conditions + deposit_conditions = extractDepositConditions(cleanstring, blocktime=blockinfo['time']) + if None not in [deposit_conditions]: + parsed_data = {'type': 'smartContractDeposit', + 'tokenIdentification': hashList[0][:-1], 'depositAmount': depositAmount, 'contractName': atList[0][:-1], 'flodata': string, + 'depositConditions': deposit_conditions} + else: + parsed_data = {'type': 'noise'} - # 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): - # 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 - triggerCondition = extractTriggerCondition(cleanstring) - if triggerCondition is not None: - parsed_data = {'type': 'smartContractPays', 'contractName': atList[0][:-1], - 'triggerCondition': triggerCondition.group().strip()[1:-1]} + # If flodata doesn't indicate incorporation nor transfer, check if its a committee trigger + elif (not incorporation and not transfer): + # 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 + triggerCondition = extractTriggerCondition(cleanstring) + if triggerCondition is not None: + parsed_data = {'type': 'smartContractPays', 'contractName': atList[0][:-1], 'triggerCondition': triggerCondition.group().strip()[1:-1]} + else: + parsed_data = {'type': 'noise'} else: parsed_data = {'type': 'noise'} - else: - parsed_data = {'type': 'noise'} - return parsed_data + return parsed_data \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2130677..8f8fd16 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,14 +2,15 @@ arrow==1.1.0 bidict==0.21.2 certifi==2021.5.30 cffi==1.14.5 -requests==2.25.0 -chardet +chardet==4.0.0 greenlet==1.1.0 idna==2.10 +pybtc==2.0.9 pycparser==2.20 python-dateutil==2.8.1 python-engineio==3.14.2 python-socketio==4.6.1 +requests==2.25.0 secp256k1==0.13.2 six==1.16.0 SQLAlchemy==1.4.18 diff --git a/tracktokens-smartcontracts.py b/tracktokens-smartcontracts.py index 035d40f..f888f7c 100755 --- a/tracktokens-smartcontracts.py +++ b/tracktokens-smartcontracts.py @@ -18,840 +18,12 @@ from datetime import datetime import pdb from models import SystemData, ActiveTable, ConsumedTable, TransferLogs, TransactionHistory, RejectedTransactionHistory, \ Base, ContractStructure, ContractBase, ContractParticipants, SystemBase, ActiveContracts, ContractAddressMapping, \ - LatestCacheBase, ContractTransactionHistory, RejectedContractTransactionHistory, TokenContractAssociation + LatestCacheBase, ContractTransactionHistory, RejectedContractTransactionHistory, TokenContractAssociation, ContinuosContractBase, ContractStructure1, ContractParticipants1, ContractDeposits1, ContractTransactionHistory1 -goodblockset = {3387923, -3387978, -3396172, -3396192, -3396199, -3396201, -3396205, -3396206, -3396208, -3429342, -3443480, -3443669, -3443675, -3443677, -3443679, -3443680, -3443682, -3443684, -3443702, -3443718, -3443723, -3443733, -3443764, -3443895, -3444345, -3444499, -3444502, -3444503, -3444505, -3444513, -3444522, -3444595, -3444691, -3444698, -3444732, -3444756, -3444828, -3445284, -3445287, -3445463, -3445501, -3446215, -3446465, -3446877, -3446884, -3446888, -3446943, -3446980, -3447073, -3447257, -3447278, -3454503, -3503146, -3609700, -3935975, -3937128, -3937241, -3937242, -3937338, -3937525, -3939941, -3939999, -3940023, -3941146, -3941147, -3956547, -3961676, -3969778, -3970781, -3981168, -3990334, -4000081, -4000252, -4000341, -4000359, -4000456, -4001475, -4002492, -4008981, -4008986, -4008999, -4009033, -4009096, -4010850, -4010910, -4010919, -4010957, -4010980, -4030789, -4030795, -4034239, -4173382, -4174529, -4176306, -4176341, -4176352, -4176383, -4177433, -4177436, -4177705, -4179318, -4184367, -4184544, -4184706, -4186183, -4190429, -4191992, -4203044, -4204961, -4206876, -4210582, -4212515, -4212538, -4212587, -4212634, -4212648, -4213909, -4213921, -4213939, -4213967, -4221370, -4235291, -4243310, -4243333, -4248901, -4256675, -4256730, -4280238, -4281352, -4291219, -4293808, -4313846, -4313887, -4315165, -4315166, -4315223, -4315314, -4315388, -4315411, -4316891, -4316964, -4317202, -4317879, -4317887, -4317962, -4318675, -4318747, -4318796, -4318799, -4318811, -4318848, -4318881, -4318885, -4318889, -4318908, -4318927, -4318928, -4318942, -4318979, -4318987, -4318992, -4319012, -4319028, -4319426, -4319563, -4320551, -4320553, -4320554, -4320569, -4320575, -4320583, -4321197, -4321248, -4321289, -4322379, -4322494, -4323991, -4324082, -4324099, -4324108, -4324111, -4324160, -4324282, -4324285, -4324286, -4324438, -4324446, -4324450, -4324451, -4324456, -4324459, -4324537, -4324562, -4325899, -4326104, -4326179, -4328292, -4328296, -4328309, -4328402, -4338538, -4338608, -4338622, -4340833, -4341514, -4353757, -4353777, -4353779, -4353808, -4353825, -4355736, -4355799, -4355819, -4356783, -4356788, -4356793, -4356901, -4356933, -4356952, -4356970, -4357082, -4357970, -4358021, -4358201, -4358221, -4358222, -4358307, -4358308, -4358324, -4358344, -4358355, -4358379, -4358391, -4360056, -4360211, -4360576, -4360906, -4360955, -4361030, -4362187, -4362192, -4362213, -4362728, -4363547, -4363668, -4364856, -4364858, -4364868, -4364875, -4364876, -4365014, -4365152, -4365327, -4366550, -4366621, -4366675, -4366700, -4366747, -4368196, -4369662, -4369683, -4369756, -4376861, -4377318, -4378253, -4378295, -4378297, -4384839, -4385456, -4385457, -4385498, -4386139, -4389212, -4390807, -4410901, -4410906, -4410912, -4410940, -4411239, -4411273, -4411288, -4411315, -4411330, -4411339, -4411346, -4411348, -4411350, -4411353, -4411355, -4411661, -4411683, -4411740, -4411742, -4411743, -4411745, -4411746, -4411757, -4413288, -4413289, -4413291, -4413418, -4413420, -4413430, -4413457, -4413465, -4413470, -4413474, -4418348, -4420905, -4420912, -4420920, -4420940, -4420952, -4420958, -4421020, -4421091, -4421093, -4421100, -4421147, -4431335, -4433179, -4433620, -4433637, -4434828, -4434873, -4434888, -4434891, -4434898, -4434903, -4437014, -4437066, -4447198, -4447202, -4447204, -4447261, -4447314, -4448107, -4449169, -4449323, -4449488, -4473417, -4473420, -4473503, -4473517, -4473583, -4473804, -4484210, -4484247, -4508994, -4509004, -4509300, -4509950, -4528359, -4528622, -4541278, -4541295, -4552508, -4552522, -4561033, -4562937, -4576480, -4576482, -4577665, -4577712, -4597585, -4597674, -4598087, -4598090, -4599578, -4599724, -4599771, -4606282, -4608453, -4608750, -4612976, -4621941, -4621968, -4629357, -4629457, -4643323, -4643325, -4643544, -4643635, -4658051, -4658053, -4658163, -4658174, -4658778, -4661954, -4664069, -4664075, -4665838, -4665898, -4674594, -4674633, -4684574, -4684602, -4695346, -4695451, -4695529, -4695552, -3961676, -4323991, -4324562, -4361030, -4362187, -4362192, -4364858, -4364868, -4364875, -4364876} -goodtxset = {'a74a03ec1e77fa50e0b586b1e9745225ad4f78ce96ca59d6ac025f8057dd095c', -'fdcb3ff273deb2a03c19333d4f4f3a22b1fedd22e17fef576559319c40450f50', -'8425c6d4171f8b1634fa1aa339b59e18ae3a585ed3387749cd2fa30d81e0f95e', -'cde8728abca696af417d2f69dda6f55defdf1f5a4bd4625df768ca863d620fa7', -'9ce989dec4ad8a39ca7461812232514c59a3618c38eb6a590ab1e693b17baf7d', -'8c3559b0ba78d1143d3ab4e30c3611842fc57988751be67d761e5c087a8d07c5', -'3803668250105fca8a90e691e07916ece655611afc07b2c6a01b028f35f59352', -'5c180a2961189dd40d5af35a17fbed7865443f6c4ef263924630d3c815606ee9', -'22330e8b2c98ef0d3dc1b0d7961aaad9b2a7bd5afbb4c71d6d4bf20c02595cce', -'c6eb7adc731a60b2ffa0c48d0d72d33b2ec3a33e666156e729a63b25f6c5cd56', -'7c84e9ac1a3d9a81868ca801966c75c4ab261bbc2d0e07050c0f25275cf8a5e1', -'d8436c30c3493dcf723672d337093bbe9466afa88235051c7981c39fa30c1326', -'b463b2b447433b7044bdd3022e271db02b30a3307f25e9c13e18eab1bd681d93', -'cf6de70c9e9e3d45d37bc6e4112851655d82dbd5aef48aedcee466fe4799b950', -'26f08763cd177e2d55080041637527a7769eb3507b023a25bc9edbe8649c2fe2', -'3faa8479657839e6ff9869b49fe5b20441e45e780403c3ab7e33eb70787a785d', -'511f16a69c5f62ad1cce70a2f9bfba133589e3ddc560d406c4fbf3920eae8469', -'e92bf6a8bddf177a5e2d793fa86c7ad059c89157f683f90f02b3590c0e4282c5', -'21976fe4a9a99eb31bd18a496328f7cb91bd4f708bb848771fd638949a5eaba3', -'d8a8b87bd2dd98ac3e5a6996f7bbb30612ecf13756c0f860968c2cb7c8cf01e5', -'dd050ac2ec951eaad4ee897c8348b5a9314a6e7d13debbc319757ec121c5a013', -'dfbc183b45762d7db565eeb0eddce74232acbc8a2c00a68a6ef628c16bb95a93', -'bb6cef5e9612363ed263291e8d3b39533661b3ba1b3ce8c2e9500158124266b8', -'edcd710fa6176cee9c738188a053967ffb4c5dca1a1aa721bee7e22b7f3b7e11', -'dd5512594a0402b914e8d852c918a3b0017e888deea1324512c62f62420a27e0', -'78f6e1dbb2eb8de746395d5c35b47ab91f51076bf3a134afa5fe5b0a44eba5e0', -'d07676c59c90b2363db301af4158d7f384dc0d6e84bb0619639ac358e6f311f1', -'38db5c9c78e6b6c97e622cc1576ebf3b824280f728c157beb56b974d5d802fa7', -'259974b79c94bba0481ad5e3b2f468380df9ac31da7dfdd0da8c3af78bcea561', -'4258e8a7530d4d1e3f1d7524cc927d0c9c335a779a032bbb2d83725680a47ee9', -'21b0b9564ae62d32eed3c9911686c20dea24e1a94c255d7b3de4ecaa720e3d17', -'5e67fee05ed5f6598a85e8fb12e207183bc4441c8f81d54b89ce6bfd196c5fdf', -'eec02efef5a505e141f5551604d401a872e33837edfcbb7e5895a9951c50aa2a', -'97b051261a91dfb4b9d591c44d9ab6192efc2f82d85777f5bf33861952d30cb4', -'3e52f39f785191b693d99859a9823eed281c2ff85669803ef85b55ea924bf790', -'3b8c7d37e16a2f7446411feebe9d141fda6edd4886998033bb3405a08c6026a7', -'0727f232cee6f4c1e10f7b281c8c5c7bb2e90c2c0fc50c8b1160f383840a8ae5', -'0623bea90559e1bb59f4134f6164544ef305fbeaa792e51f09e03706cfe35b79', -'67783a84997fd6b6099267afd158494a971c3aea6ff6856583d778ff5bcc2a0c', -'441c222e9953c6e4278e38362c691835a3c7b6f09f036bf6918b619d0e16cd3c', -'3c0c391d1ec5db8c6636996b6479c25a4a939fb7e9f14d899d41431c5d0a6aad', -'d5e61452a5fc98cac6a0c2c8eb5dc45c345513f2bb27240d66ef3d47a11c46bc', -'3a53a7b61f0ff1c09a25f2ffcb3a97ae0ec0e3b0eccb5e82fec4966dbc0eddcf', -'a433e8f2e7d332cd9574d7325b33720c75f459870d5e060b506a7c7c17650b37', -'2cbc28088cfb983b9b8fd7ec7ee5abcac5cdef07e706413d4094c2caa7020753', -'7edcc427a565a458ae81dcc9a9717d2592120bedd632a17d4ca3fa863e08ca81', -'27ee5479706aba9d37eb458e1a51657b418dc1c9574ed37af763d7d7d7178937', -'f38996915cd00f7bb6ab33ca522168739e4af41ac718ec77b9e7974687f48ec6', -'4db4f56b711720b1769a70d834ef3138b599143d0dcf82c1d3e22e44201cc1b4', -'ad50d8bffe7214473b6f8f454f55749d23a26ab3fc854d63e1ccc808045d98ba', -'5a36fce4646358c751b5403ec5c7465f1b11c8dca6d86e8a9cd4e26184e07b1a', -'3520cda2de65249f7629683c4b8f3efb15479076fe9521250aba2f1abe3f2ce9', -'b57cf412c8cb16e473d04bae44214705c64d2c25146be22695bf1ac36e166ee0', -'ebc99f41c4ccaea32bd9dbc251515838ba47660b7422c7cae39ee3e2ae0107fe', -'e6338071b4247003e16aae50e2696d42f42df116b928122bd94c3c718fbd70bc', -'cf54e0e1b12065ad5ac307400e19b9097f2759f4ef003753e0938eb6c1c36f00', -'ebc015c8c57acdca1020863537eaa25cd00c9ff71c4dc3975b3d4104aa456488', -'b2b4e8bb8cb463e0295f9b639c29aae443eb8e7911551220e7dd45648a4e17c6', -'0e6ec23a1755217b64a6bae24ac14a326a427bcea88c9e4a25a6a89ab6b5e1f6', -'55f144c92556075e6980de0febf5ab41ebf34af4b15eb60fa115384d2507c460', -'af9ca8eb285437a637ddc03cb25e06f15ac650b9f4b8529205380410b11697b1', -'a59a7a3f24d374679747256790908e9eec841a2220e51e479f545122e2181fdb', -'16a3a51868c0e4461958fbd725dca6c2c8d8e9ffedc52a948fea21f4e6ecbf55', -'dec6a4cf1d2ecfd1b36eae0139b8e4fe6307a44af1100f805511860d43508e48', -'f4bea61cc8831a51945fdd240ed3bc198ef3205f4dd409d13d3a36f050a808a0', -'44e17058bb67046e391027d0695cd2e494242406d0b7cec0748645ecaeb97ec1', -'cb36f02e2eb97984a5de6a22123e989ba08dcb13d8c38b101f743dc3200d7490', -'322f60f380573876b5391e77b1296640d97de56d6efcb21f83d6d010e0820165', -'ba8e3784503f5b728764ca7853fb3f07efdd68a86152b126ce8a9ccc0a85f30c', -'ac6e826fb63a62b17f4603202c2ba43cd20aa9e362ed5f7419b71844ecaadc65', -'1e6de7e90286a211335e3fbcab1022c3561d57ffcfe4036a556fa4c58b032ec0', -'cd4539baedd99a5aaa743a2ed2babc55d2d0042cb95d71761f54e918571a57ee', -'6635af4bf7b82f280a57b9696227e79280b17442ad01a2e0902b513f1ef7c017', -'d219431684852035ac19137bda6a1904461d11fc8d3a66aff3fa21139f4ffde0', -'7e4b1e283602645584b24321417dad922bb8f65b3b983c924a047e22b9ef1c8a', -'55acaa10d9cdb37636b2b5f97054fc6a10ceb1cce310009b2f9ff5e8bb274e84', -'13e8242ee6c8c90a57e902051ce38f3c87376a6672b5be132d931363ecc4ca75', -'3a9118d83177f6e9fb8d46ee97bf1e1390cac2ba24ce1e3982086c910053ade0', -'e6f3effa2b1d885e1bacec3e7ff8256c4b55b4e0bda0514508ba4fc44ce13250', -'074acad64d28f63746616ffe39dd9e1b03c56b80809bf35b02b545f9907564ae', -'01f560d06ead33b2dabba9b9fdb44ab9ff693e63c0033bb422c991a4ccaa3a9a', -'46c5734b45d45276b69364ffac6cceb789ea667853760750be1875847d226f37', -'a1f6f8834ec597b23041c44761c93af3f595941dd23eac1357f80c886c601a8f', -'4476e804db749a21d5d5ac809a487b4f31b9f4f561531879e4b507abafa18953', -'65c1a4cb0cfc2fe51107abcb77277f1ab0e16f985c78369599d98f684fb45144', -'3f71fd1649ee36cf66ffcab38bc59dc18aab2995d37ae1e3dcafe9f63598c4bb', -'61bf9bfb99417054862fcd5da7cfc8c68dcc477272ecd3e821fa07bc7d2e7a70', -'535c996c16aedb8df875dcf48e38242e79b22784a9297d663bf271644a747951', -'1ab70a9de6a8deeb0ba8f6c4ca015d60659c90953a7c8a1f3215276fe57b1fb2', -'b93810c8ab06676a42907e2b116cf8799e08c4c0f0829d77b1cc9284f308a9f0', -'612ad2b43229a5b02714ac86d8d119269e291872885312269b4d9f98c0bd4ed5', -'c1ab82c2a996103dcdb9895e453b4a8d991a14ffed79505c752ae02ae657076b', -'9bf4006ec5f4f0af4512318dd90cbd24f3af45a6280a444164a67d5af155d85a', -'89e3dc0c351d5554caa013515be89865c128a5424fea363cc6d43b53981a4290', -'911d634423646a12c7a0825b3d2dbabd6a34231835318e546142295300705254', -'fbae58129af3c09590fbf1781d7b8d331e521f8bf8e51cf22d91fecf34d68f79', -'3a2b547fb501a376c0d04fd883c0e0fc8f226413ac175ec9e345eac7611a16fd', -'db5c739bcdb88f6ba8532e66ca344dd517c527a3a38793529b53ae133c917433', -'536bb47cf8cc0499588d25ff4185e92c4edd77610a6aeb92cf551c2f74607af0', -'5783bf578fcf8cb7b193d82d961ac2b82cf3767e578f67326c96373a4feab8f7', -'d0b4e46302d55e5e08369e595df24f58726eedde6004dbd99d04f740b9e41132', -'7a51b3e2301ae30402770284c008a5905e56e534efe6dec9dee93aeb9381905f', -'db4407a6f08f08e8fe375cce5aa72c1ef1dc03522b7bf5dd625230ab18485675', -'951e7e2bf6d42f690acbcb7a0cef8a3c5f58994148c0461bcd8daf417ea8bfda', -'22e7156182f9dd6695a1f23108da144534ac783b42188c84913d99df0c0cfee3', -'ab67fb7852361fcc05e7d5550fe7a30bd1211718dbca5a66ab26892a7650c4e0', -'57caac52230ad49aa6fbb83e6d2fc84f48909ee65197034f6a8064d397066ae9', -'47c41cc4de57abb4e9fa7b1347d14bd62bc7401bfd9dce6caf11ce4b73fd94ec', -'3addd5b84ea121bbf6b4044452a806bd94adfbf35d591932229846509fe616eb', -'466e7827eb7034bdf6a1ebba4c1b385e2faa1dc21e418e66b535dcf5a73d88c7', -'4a2640abbd6921cb7ef8fdc8a6cadd27da44539aa10c5e6ad364432824bea419', -'1fd1e25e703124d294c69c67852cc1fb2017e51f37aa4b733d423badfcf90a52', -'e3ad816a90a4320d74d52324c5c657041ef29219fd7be971f51917e59ececbf8', -'641d218c815f689a461565789920d7b86ecabd1a324611f039450be91b632a4b', -'9818246afc1b90b717bb202259ba9595a82f999e3310f4369c0c50b06c9de15f', -'b8628b077b4c472e4a6ab18a7f99f7006317e7abe909f8dbe43312780cd8b0a0', -'3788c20cc073baff9b9505380d7522f2dfdbedabd31fa1326347be49adbbdcb4', -'e65c8cca158865575529159c023fdd83001fd7492e0a854191f8cbf93475c494', -'d7e160ef8119f91070f3e95426911c927b87a03cf5374d3bd75ceecebd60073b', -'6db604b62b1be5fdfcd3fb51611f7042666060c65a5217deac5c91a9b5b10453', -'e7b24ae11da6590c9d296eaeeb26c080cc97b20c73793ec205b91ed43f3816cc', -'458b8494dccf3cb91aaa49131537b5008f699004fa3ac4157f9e48420bdd9662', -'bacaea9cb7e3bb62d9e54506e038c9daf7850a7342df047858fe1ff48597a3a9', -'41d5913ca22c3ced4c08c6f8637b9e067f2d7758d0d0275dc704e8f8b64b9f7c', -'3be4222924e4ff05a6bc121e069ed51b335ed2f6cb95402593c8a27417c505f0', -'72ecc2b914745cdb0d6421b1422dfbdba96c0256e56d6d4c1d84ece56d0e3e18', -'3620e5beb80ea8e4aded4796072399a8f17fb782e5736c8d5577493ec3794702', -'2ca7477d0425c676d4e28e5b4e1c71f4b12a16ebd840d0595c3937f23c3d70b0', -'12215cf6c84e1137cfca91c2c1db822eb1caacda9befd008c2adb556cadff0f6', -'40fd93136637c31f9772c3f846cb857988fa2ca59a77282ff1c54dc754f95051', -'3d011143188a0a931bfebe76e77c11272bfb543f71286690072423bb376ee872', -'50ee03d685ad9bc06d07b049d041ca523afd46439c631b08cd684bb8b2fd5929', -'5c4ea2a61857a1179e861274ae292ad22d778eba1eb04d5b02b8901461480baf', -'86f157bb40c266caa5b7b6212fab35f32d6d059251e47e799405457bb00720b9', -'cd27fbfec5083a79986aec7d772ba9695fd6c23263c2252a6eb84dafc7fb9ced', -'e51d497ae3961ea7bca697f7347fd7156c17310be5cb9b956e6fcc7438755f57', -'392fdd08ebaed00373cd6496cde779f976a7928f02cd9cfa7aaf96bea619f6e4', -'d3a8cf88f949bb068c9ae6118afb0373a2929713a165ffcd7113be4ec9004945', -'7127bffb2681dadc8090087261676135f2a063923d19f4683816bf3a8061dbee', -'7669a68489ced1aed50ba44d8be50c6c2513481ae27a464d6c29d0df66029b4b', -'1a9077b6b2ad7c13442b0e5751b26b5ad50e64c37eed2d782d10c72b260cb46d', -'59e75e41cd2966a5ce39b8a7bbb1e89ccee203fffaade7b440c216bdb692895e', -'93638c3080f030a1c169680f542fde5c5fbee9f119a2bb78ae6f28fc4616be48', -'0080c6a7155016d55f9717851aa2ad5a9571d3b03fa3ed872095190ca7ab4136', -'260ebd1d7f40c9126466c728d8504c1fb9492bb59f9186adc91c5ac16ca5daf9', -'f4a9131c8af63f8e59c96745019d621d04c24beaeec018a49051890f869e1588', -'8fb08532dfe79c7fa5537ef95a0d1c9c806c134707a05453e62c92c59c45cb0b', -'4cf0bbfe84e73bb22ccbe802a5f90301dbb24573ce707061db0e4c995551fad9', -'5b1b2127115f71e2a10d32da321b5b76b9f6ad0cd6ca1c1dbff454a6e783e826', -'13822b25f5e92870c9fb5a6ad09ebbe0ba3ba2c909a381fc41fcab25e3d2be7f', -'4a26e4bafcd460e38ce082c44ec49725dfe26e5362dd67fc060ff21e273f549d', -'e6b7422316f7ff5d7538a3e48d5860edfabac2d475365addda2f822c45ba56ec', -'7ed1d7e63b852626dd29be2553e9c88566734282220d67703a329660776a1a3a', -'8309340f71736574268497665ab8f31948478988d2f7a9c26014c0ba7fd521fb', -'061c7f252198e284d5993fc1798050f56f27c6b46aaf90fac4df0df326b28e4c', -'ce2685d884fe5c885fb0279e7745dacee38348c5bb8cc629c72bba589943dc3e', -'9d2a9d6f3fff5645eda3e1cdf8df56411d4a92ddf7f6563d745cbd36ac79405c', -'622e602433049439913c9507bc26f45830055f5119b8926e63af6d7f81ce5138', -'60d072af2202693a2467a097b2bc74383508759c36a6fbb94e857538a9e618f7', -'2483f05eade500e24d34f7dc5f1443dca078c2c8c04fd6dd0b87da7c5f19a3e2', -'bec8026fd4a3d606970f37a3c049b9610613637c35eeee15854b8744867b0735', -'092b2ee21b233f81113aa0a0af38879b90b16021ca215b4ec6aa53b070305b49', -'600db50af61adc64812e9866cf789b67535bfa48fba3a82aea023dbb5a6df170', -'78ba189416344f22c50ad5006f5e612115bc903efc97757889fd8d706bb81f5e', -'2dcbb87dae48f4cef02342ac1caa6fe9e293e9ef8b0e109a640430dee8a474ea', -'dd8813ca9b05201b7463a1cf337a177749542eba1cbaa8fb8f7a02185dbf8932', -'ebab14d8926ff9b00a5a5d8f16747fb1008fabf0a91f202adf6d379a77d0318c', -'9219e49b8a402a185dc96bbde1d6e5988b34dca4c7da28c028cbdf0caacb3755', -'2efe394a7af45d0d631b855a44a90a37d0fbf457301e3f02ba70f7dfb069c3e9', -'8992e7200bb05a89f6b6141d82b69d9bf74b30bcc709d06c33b475902ea59e99', -'93779565a4462e6b912deaee052f26b092b11f669dcbabfb6de1b43cedbc1946', -'492d0595a3048bd9742d632e2a2643e22a3e0dff16985ab678a64d5403beb1ee', -'45a24ca98a644b889f65b31e27316bbdf5aeee3d4408ea8ec247235ed044e0a6', -'296002fedfb70ca513bedbd5fe0e72d5ceeca5c9ac633ad1d98879887146a5eb', -'4c7bd839fd63731012feb08f4f219370fe6febf56e4a709c8b8cc1afa3bac65e', -'0a10adf58dfc0a84fa6f093bb933f4bc777001c7add52b60637a18a3779e5d54', -'98981e00f3d5c7be41a8dae6e062d42555f2bd8672e9c9a8dd9375803fd4267a', -'fab5f3e8c9849fc19105f05f28f31d297a04d70ef3d85a6cd147d53bda684c0e', -'2790937711173f0d6e6095308850945408218fd5823345e2b3a2107aa65f4dae', -'ae5fb75ab5b05ea54d6089023e00ae797d09449e7e1b69f8250ebf9bdc02bf4a', -'4f84f7296875f76ab5790e176ce4284e36558e4d46591c26cd66f7daca412ff6', -'bbe2e76c54ed38930a1940988a68abde0c20a313b8d40e29cb0984ac77f9f971', -'45d44e43a04b4025456e2e6f265c5fca05245350e817b79b28fd97e3212f832c', -'172a7646479dcc6482f88e7f8fc5fad88522a4c5aadf72cda35ae84c3f4fe2d6', -'4fa284945a06ee78943203be7833711b6fd22505f87efc7ae334c4897da57c80', -'2795f8838e10ad379a639063c17b72b323f2cb790975198bc8ac0ede416477b5', -'db857c67829c6026e1bbe6dc015db074d14eda24a576b1746781c3bc5d14c0ce', -'9709ed076fef74da5ef153337404d88c25b54b6a657b72c59d8325149ddc93de', -'0dcf380356f6d2d7bcba56930e898b83126048af6020904d6196a81885f95b9c', -'2540e7376a10dd67d07f5cc2423b05a7e1641a5631a03e783701940e820fffc2', -'3975271761b85a03064b115de71fd27b1bcaa226337a35e7f7bc229a055d9c3b', -'c98477c4016c5e5efa9740158747ecc599713304d770dab5841c182bff5aa62d', -'b3b9cb17bc96663a956fadf1a8cd1d09a323eefd1a5c887153a5e05ade95283a', -'7a1fbd32552fb1fa6f30e55e17ac880affbdfba7420ec4153c90801d89dadcbc', -'49b479660361c526944d3bd4edd7babdf04c47e0b9d413a2d42e5bda0554e053', -'25e901bbf4c3a95b499ec6db269c7685c3fafcb2294ad23430ff9a38fa732d6a', -'8827a9b2baf1e4b6bc3a8f8bd987cba04064613aa035a10c8df17c87762dba7d', -'d04fa3810fd0275502d93628c6399d1f6ee1e891f4285a3bb99d3f83cda6211d', -'4266ae72d5ee29b527b283d137f9f7552b926b21aec867158fc8256df08c6b54', -'9776901f56b85ab35f50615603157893daf337bfa3af97d42d9c6d5cbe98c61d', -'50cf0f4dc221c801ca62bf524309249b5dcc9fbaa8621c20d3d152348b3974ac', -'7382fa53b6d64b269fd9b326ec46104cd30480c8e7b193ca441c70b735621a46', -'ef4430106dbfc1bfee425f4a1288fafcedae17636e3e44483ab868b729a7cdb0', -'e16f57915e4fcbc535a0eacb7c46d39decd8594b6092d435e66f85ce4091b600', -'adc15fe031ca56ac63e317a838ac99972a19cd63c7294f9c53960080be0ec289', -'dafb9bffabee8044994e9b32d98278f8a0e74647dc80519d5f113014f2142b46', -'763b6ec4637f426f6b41fce6af7f23a3537925aaf3b23cbfdbae3227f6930a4e', -'db779d26caf9a11881630256cecf4cede992c616253af77958b706835e4f71a6', -'51d4d8ec4a8536041a80ae5899635162347e316525271659c99e0f79389ffc20', -'e118f346408aba460c5acc78d416ac4d78c93cd0f3f8edab2bfd1d4777e18ced', -'f12664c4ce0206a6b7307ecdc824aaaeec0ab00bd31608ffef628e8a35d2ee8a', -'8dba8a73696e6d0d61cfe7d6b3d1baf9d17a4b336edb5ce100f8fdcc9015f1f1', -'090b2240badddc79406930aefe159d2dce96998b0c4926f829fd28052cdba11f', -'ce75b076f7956692976b3dc2080ebbab7a1062b908bf1c4a071bd404726e175a', -'18d4d6bbebe8430b4c94e2e3c17ba24cce6a3c1a2ab7e46d103e97190aa3db36', -'7cbcc0ce87a0a9f725ee7200a7e86c9bc7d6247da2a96aef37b7ca6652563d88', -'640e2365b73d4c43d84d594b226d017ff520ed8059b889d295c0f900e735b29b', -'9684451f0c396ea9adbcc86fb4abc7306cc408301752d0a0209cc0dbfbb2f4fa', -'a32334d2e357e04f6aa41feaf23e4cad58e0ee7a718dcd6b1ea004d78708a672', -'15e9df0ab69520069311a5a8c20a1e0eead8d97547e4a848404d887803af1968', -'9f6f0a29256e77c8972c3da1a24b3f765dac2fcdb93820cbd88b7f82c54da3d9', -'320feb73d8c766dd6f86b95a7420469a2ad9a56e92c88598b7c2838db5c90ac9', -'1e3e464c911bbaea8c1b2ddc1b6e7630fc773efe77cca7792b9745f67a13ff96', -'988cbcf1afe194c59c04ee381787d28fca9fa5049c18873ee001f084acc6e448', -'0d36855b7571bb8cb95b715a042fe329da3a8e4b778f9d75823e936a0e549312', -'429cc35d04c057bb691eedb0b792bc829b6fd88cd2eecf72a728d7d496d8c30f', -'604c30546332ca9fd30b048303643dde9c7946615fe6869b730d16fdb7b02878', -'6146fe7c79189d69df963819d90ec4932552dae2db32dade683c6c63c76dad84', -'5e2a58a43ff166e931d08a540685d7f039017b4573682e03dd96543a7eacb73b', -'af40d8ec09b302be543caea9729c43042fe84faa0a66d9841055081d913c2093', -'afb884d94a0fdcd789e30a11e0e2d99361a624955570560c53e925f5bc3c637e', -'b389de9d41637bb5917fbecae7b8086d5e2a7e97e32be8f3372dea99bcba498d', -'d4f1d0593d2c452839ecea58caab35f01ee260ee24327a97fa1da71523ab825d', -'6b307a5ec87cb3f56b35717963070e00c60b6da250e422f6805956cd18820d5a', -'f926a5ca4f2d6dd6d47123ad512fe52f20547b5067765c68b1c51c038e22607e', -'7e083b829d991ee91486d7fee10276c289cb47465cf9b5113fb6ffcf9ee8d509', -'5d411870089af67c73b83251ad7fa198e26963684ec1fd6f53ecc05d0d5a3fa3', -'073a7a3001d559d0777ff559ff4aebe48dcc7d53c1876271b9cec534c8502846', -'e3c3a7a9cb9c83940f864be276ff6307934a1a23680269e654d00fd520621802', -'7bf2d61f2c128435cea56eaa869dffc5feb705ddd6b1b0752092caa0ecf2cf5a', -'9fd3974b313b0e7b66802259e39e493f77976fd403a02fc006680b5e310e6587', -'33513a8fd099520b3d7797153bb1f0cfa3afaf95c3ba12ec8c8d9936d3851776', -'932208d88197c89a6a819eff1d17515f9a00ef68140e7dbd8711d59fd3344ad0', -'0594fff94b6c5eef1aa3418f89a2b9a815b0b78cd37a9f5bf5e6c7527e341938', -'f0e8db89dc4bb6f1d0afd375a7ce62a1d6a8d30bead1a9e7fc2bf0a307402209', -'3cd8260017004591c8f66263f266f969ced86b858f2e3b43533d349f5f6d4167', -'e79b02d8eb1e72278d5d23db1ae4dd779bd834e4de15119a05f37fa849662277', -'c128256462490241ae90861f5ab5648f37c3579828588996f4eafd090209bc19', -'ecbbb79b86d4e5c55bc97273290c0b1989d6fe867d219fc3ab2837981a586671', -'b22772b8fce88d52a4280bb991411b25de1c6aa64da8889cf03548d95614900b', -'01f5c6de4661bda50e99434e37fff96f6d113e1dd2907f0f768816dca57a75f3', -'ee3ced889ded3e7484b61f8a591bff2e67e3b8b486f398e10db9f3fe74445a82', -'8a90dc410bbd5404421af830def2b74e2baf8af566524ef018f0a6f45443538d', -'f47160e6901aa364a49a122c37591bd6bfc3091931931c66a87cd8002857c120', -'41284ecc6d052cb2e2674a9e78058a402a201290d8e5a0912cea571f59289ad8', -'4d328859872d13930f86cd367c2c4879efe0d13114aa233cf8fce3e42274ff92', -'a48e6af747934c4e7441f35c616cb70f4793e4cc353c30cd99eae68fad8eb178', -'3de5562c2b42023dd09d83a53dd49c3d3f15dd82034602fa694fa9f197fb0fb8', -'70742e4750d2d41fa9249ec293cfee40eb98ec96f5dd9b3566180c2ce491e59b', -'9c18f5f2f520793a670fd7d13a81ed0b5b2b2353b80c1df9a26457ada2070aef', -'41dff580778dc0d6913456134c3c616714e913d049363a6ef2320984a900d0ea', -'33212388c36ef30a4a2344fb0ba69de51024ae6e9437d5a7da62bd0273231f9e', -'ab57f854266f4d74fe9e44b59153947a7d87719574c50bce7e987294d759acce', -'f55ab35d960b8d8f3b9157e8ad35307d478b3f35f1a78e4d48046b3cf1a58704', -'1153dece5a0fed4ba5b5946578df9cddcdedfedeefd26b0e9d403c89774c7e63', -'aac7e91aece0703ee8229d0347deb38dc6c5194fe19d65566594ebca627c2426', -'4f0d12abad3bd347134db8b6c7ca9d4db2490bff589ad63c4a431ac52b77cfed', -'ac4cbb2c073b66eb1e002e0d009a209b7b407e416f361ebf3b07df8f32f2f84c', -'270bce14bbb30b331ea04bb785118ba2460e780eca07410c019596199cee6f4b', -'4d1ec4d8e74b2cd7211e8effaf24979172bfc345e3ef10248c67980feb17969a', -'df25f18d610e8cdeded67016f8d0b48cda71691627a66681dab788a4cd92460a', -'3d5e468a3f1aef9b259eef7105e8eb5a0ce4c8d3a2230cf8fc036ff0fe61b4e3', -'e62f0d358a697f8863bd7ce8d29442661a5fea1e20d3cee08b8441919d01c8f1', -'68c424677691726381d4b80b664718609f0d7e96ff21ee204dc6afa3c7eafb26', -'386ab80b0dc9609063101c4408abe43f3edba36b51f5dbed4e4349a201a9310c', -'62ae5f6a96afe8b2fb971777e3fbf8daf1dbae26ba049dedc38e137ea1c592dd', -'74baa5e9183f820df28cac718fdf1081333eba1463be6b43be8534c757aab558', -'f81031a1c3919c0f04f467531b51da84cbe92cf846629456f6d837cefdbe4b18', -'6b3c0b47bfeaecfa277e2cef7ca9833e62abdc751c4fe0c3841d35185e09e000', -'a74e8a63c64f0f93dde2eb8e4080e280b911abd3587e1e94d6cb310eff4d5c3b', -'923ca648c0358452d2d320f76435b0991782a9810fcebe113ec1bbd90676e051', -'8fd5989e62ea9db5a22c3321b559eed0f71c9113659c4c898a2f6bd1cdd177e2', -'3944bcc8ac1eeefe8ca42b164887eedf09d7831560ba3b348cafd2d8a688f9aa', -'b7f1beed64f8c3b50d7ed2aa40ef81069a1435f2070e608ed79d6227561ebdf1', -'c96a0993941fc28892a5bab0566b7efe5282239f7dad2e9bf32eca4cd7a2e341', -'297fc73b91a9727ac6c68c2301868d1d18474638dad1939e37e92308584f72a5', -'6f62cbbaca8a3c1801bed061dfb25127e9ba5180d1fd62259c62be763bf1e060', -'5c25c6297cc55a73a85b9fd05b5e7f062bdcdad2638d938cc106a74635328a48', -'0f870c311083f9066cc1536355eb9311dd4d4ebb2eb3f4be59a68f82cf101ce2', -'b1bd3c1a5148bde436c6b5fee1c6aba715e90c9c796f7052737c1d9271c11304', -'f01eca1701776198dcd54facb4ea6d0430eac1f606ef3cb60e681d6866619dae', -'254bb1d8c26bb655db414eb8da2c818e5b722102de88533e39710e5a8fa189fc', -'d643b37250556456341f1e2ea3e92917e8979029207881d6b5523185d3f982cf', -'3094eeb53e4561f924207347c7eaacbcba33c87baa805b9e861002b48bc80198', -'8e122930dbe5f9d7e6b2ddbdc6077e42c6575b0513b7dc56723b74845b31f394', -'465796280843bd23899514250aeaa4604d5f93d0de32732d906c26356c4c0272', -'ec73e56997ffe21a8989a80b7b1b004ea81c4f9209295ae4ba58c20ff1490f6f', -'a8bfd689e82a1683ef217ec4a365c3723a327f82a23748d2524a6c9f38874deb', -'352b7579bbfee90dce0a78092e5af97b6c0e9f7722106859b675b103ac70ea61', -'4e217dc342815642c42a85e80017879d1fec77e97c55fd8982b498398a4c8141', -'677ef5637eb541fb9491f420dcc146b3b184dc9e232aa57ad36ddf1529f69622', -'16a8dd1a35c2711c330fa3e4ce108b48581d7f50bd39d52774a82d6404289e1d', -'caef4776c79795a8f5907c99d7d8a64ab2ba3d2484298b6fca6247f6c92deb15', -'a50f3d1859240d306d97b0bb9fee5be3e61dbd36744b57051a4b01713c0b018f', -'b8a4a6b56ff5ccf1c29a1270b760f799825cc9f875921457132080cff07a7ccf', -'90b7c60f1a910fa507273cb1c9e9688fb3371c501fa666ebee35fe0fd6876864', -'a6e68957ec18f9424be3c35854e8b510ff69fd2fcc245625c19fe756f8a6ba22', -'42622508d48ba6652c8c5e057a9ca0d4dca52df1c2c8f2e205ec5af84a4ae034', -'d6e330a0fdaa09122efb29026e6b29ae01c67dfa97152134699e5727ce8f1a8c', -'3ef8229136529cd0097b28f71a3473f82d37d77bf30e466d1a87ee990243b926', -'42141524318ce10cd680465d66d24839cc56f92b8c8511ce237e2f8c698b8acb', -'53aa67d564e8cb18c24be81b694cd6796af777616d91a563297610bf866664ed', -'66202c052c27c4947a892be7160829134f92e15e520d995b0649c398e5ab6c97', -'e37d3e48ab530054cc6001b96f6ff65d7fac342a945453bced9e7d0e93d2ce72', -'0ac8508da892c66f210fbd271fbd105659900df11d49d55fd70ab629543332d8', -'3f86a17910c56e2038a0bd4a9429754921c3db3b231981fa7777a0716de322d4', -'d1f6f3f6aa4aab63a93df3329719f0f17ce0abf6de44f91c74189fdf79397f03', -'7160c44006ac68d56b2d3d8ee9762aef613c988dc2bd118244edd6e5fd2888f1', -'cc7e88c6ad07001d77771f8aa8b1df8240344112d4a33b0df6c201d0dfce52e0', -'c0bc8fadc1aa383211db4d8ffc33fb42b1a0c4c6a8e41b31bf17cbeef6ce256d', -'ea8028180dff361f39a1f342a5df70a29102da2808415b7c4ad91fde82a8b50d', -'d53845f444884348f2853af02f61f4026f9cb587f934a821666263a07ce4bde2', -'4da0c42cd50b30f0225399ce606df889afbcee48a476704fed5d5cd06df6903f', -'7b49f85631277f0eb805c0d6c1339c2d06e1f7245147bd848595681e26be1c16', -'c25449daa3a5a20c432ffbd7224951942eac76cc752b8d40a5b8c0b4aebc643a', -'e04e97ea87675d30569ad0f4b87c468a3f5e2d4bdd8a57d194d9dc2d694c81a7', -'16ce4899882e7903d066f561944c4eb93757f91a5656b7950452db40102d7fef', -'a576f5dcafb9b39fcc8ef7f306b2282c60d5d25edf46002e14a26fc23ff9cf6e', -'801bb9ae6e63614aa8b18d7672501952352c8e7bcb4d435287bfa358b1a6ceaf', -'c66af0d4b38d60db6839e96dd5e51c39bd66f0eabada130456011aabaa82fb03', -'8c84643fffbd3b78330eac851e77b6b90b3787996c8909f276a01ad0e4bfe42e', -'7f31a398614e8dc5aa6e4c00a84684641a07c920f0769ab1456b0fd99988c586', -'4cc5cf690d91d4b0f17482d9b3cf37a8cc3cfbd9a80031c7d0ad83009e3eae4f', -'62aa36f441c3641b07a7e8bc517920f88dd866d75326f8969ea759067bb83519', -'2b3c96cae11cf115ce41ad3ad432a1be964525ecae064b297a03b1ffc8445c26', -'c1d6efb5b64f4411884f42c2222767f808f3e02bdf288ab308669e45f453ab0d', -'3144b230521841fbd05a4c007073ada4c01ba0db361dd269ff67619741ed01a7', -'c699166ed9dd58eaa1815fd9b940109974286b5f827c9ebf7f4cadcd235e0fc6', -'8dda730c35ebfd18471cfd22a9d82c61f43972b0f5cc22046277646cf5547954', -'9bb296afaefcf0af647acfacbb8b823f8d3a15e5655f139471a84909a88eb94d', -'4e93768d652cdc5ee161efc9f16318e100de93b995cbe0c1badba2dbc140b0c1', -'92f9f687c84d3c76b9b584fb974369c81fb412f2040aa1b728c6cc5db20f2810', -'1c1458a772198d641f5e23bcabfd11c8e45881762e419c262a5b2fbfd0ca5a24', -'1c0a012649db8561b4002a417897418e7127fb756b025a542552eb63d842c80a', -'c80d5f78a14cee0be8eaae8eecd93c79e9341aaa77b86e81c931710389072179', -'aa0227a4df7ba5ccd73828333cb9d9e50cdcf138aafdf23102e95654a691dd7a', -'1c40b7e8db498b8776b70e41a5e364e8e734c9fba441cce58bfa6ca11fa16742', -'e9ec6e6c690da07b38ba005b26ba97dc8ae201b5fc70978501a1ad973fd3145e', -'3dde18eafa3d4fb8deb7a6314e3448dec3ae4ee240ed9ad018f6a3f5c22fccbe', -'d51972193c1ab27686784fbc6bdf57f2ab3512db10d087fa7daa9b223b4dcd25', -'93ed06b90fd50dab61dcf147ce69c352730fd73ca0c9d2afd0b4da3ed8a01e1c', -'ecd834cd2b93485c58d01cfe47ebf3de8e9e56b395ef5bf29480e030b5d317da', -'235e0fee34ba0972c51b174a975fa97deb0855949962a63faa227e6c89827d9b', -'e3a0472f06f169a06bb26b2e3f9f5cd0d91051f324eeb8518f39aa989a013fa1', -'8d12689f78116526aa0d6eb24450fcc52cd1417cfba960f8e49ec2ce7e0ae146', -'2adba391227f919132be08d4063328bcec9edf8f7d3f3ffbb9552cb117eaf9df', -'4938f163678066ef336a0089ed40fbb329d29168fdb54a4417128796a7f28677', -'b4f00c50d3a326448724f0199c41f9f6b375b1fb09d3f08dee06aff50cd443a6', -'814d4127765aead557be45a54bf08fd1880a8c8d5cb69de2cd54ecf0b0ba9f2c', -'44d4882a9c0a793ea5e77931109d52e943485894718c37d2190a76078b1b0f71', -'14503fc26e9699b768dc90f32d316cff443f19f5dda3d264454eb61674bd973f', -'2f8c794eac8254b4048935104bb6cafede8ce24543b3ed5cae556d2d0a7a4581', -'dabc14dd8539ae18a5a9243fb6c78b6dfdb348bf99c1ad1db57080d9b01ebfc2', -'514cd93b8d3ee13b807dee6f81071a5afa7c6bf8e6398b1f8a2670b8641410b7', -'1ce47158d3d4b55d637bffc72ec4300646477682a4b07954bd0297b6891c725f', -'e3086334be719c20df144302013188714ab70a9e712957aa397b65e197d5a260', -'9f64264fe373658c52703429a35a8ef451e78e280ebd215110acacf41c692062', -'9be7ab557421e8164e2e890bc9e9c393b911e2e7346bca586ea8ea746db5ef82', -'77de61802eeab102a1c8f835a550d3158d5f19c3cfcb0e2c341ff3370fa0cf78', -'5bef4e0dbe537b32135689ca199df434255e7914fe695454832a7ba58924aa4c', -'4cbb8510cbc98a9576a743a6848ed2987b3f1c5701152dabbcf2587ada7e11cf', -'4d9a2a4df387574c5d1df5b6c95dc72d3976778ab4b440ce665723962470414b', -'2d182aac179091eb1a452ca88b928d65b353d06b018ce76dc405382cd3e7b32c', -'1df4967e9866867aa6c108861b41c60efa4b430aeaf352274dcd1716a86e22e6', -'2136ad0d7378afea9d74fee86f193ee321a5f6b76cb3d4f00ae6c3fca0b73468', -'146a3f30fafa3bac8eb2cba7488e37523a127dfa9d5db5e62231ed073d4db98d', -'dc1d5351986f79b13fcb55dbebc14b58a760a2cc78e493782f363039031dc0a2', -'988d61985965f6319786edfacffc7ea6c60d22482257e816d0ca32c53d12a2d9', -'a04ea0bb0a58aa953ec51e3e52cbfe1bb140551f46c05d1211e01c43675d59f0', -'2b31f8378b9a1d8dddb5738490e88aabc447c3325fb093ef2675d888c40bb5e7', -'87c37a2e48a74655540eaafe311c6c83ae606611a78f5d3eb0dca7dcf0eab7f5', -'1e00f056d6bda9518676e6f30c6da5abd766ee36c79ef3fab11d3afa01854eb5', -'354dd562a379f18f6182d377ff1d73a15b059e55d230e26b381d2a8cfd00d56b', -'0b114de869ee0665af1b2b3a8732457bbdc404ef009cce95b5cec8c2603f9ff8', -'f9cc18d4cd894d1b61d9de374d9d1665af3d10d6f3342156b85c0f0ae0c73cbc', -'4a5ca92a505ba9a09c970d746c33ddaa206584ddd34e2e485b68dffbcf621cfc', -'b9a05501f19a137bcfefba702aad7628aff3fe6ce2cb8be03796373dec279907', -'f1ebd02e1cdf382cf75344a6289b8bf132227350fb46147961bf74650d38b0c5', -'466acf103d5e3fca2f406e97496af96dbdbba99ba5204e2ef18584574c12fe07', -'a03f2217b1781f1e0fa0a5eb5ca11a43c6c88f0374bc54f3930eab57247ae089', -'e6bfc52d2e4f5fe47c5d06746b6ecd28bb083a9ae7338746578e9b6c512f3878', -'f4c2aa16e5a355b5839502848b519ccf28014c7e185bbc5ab3bf787517f247b4', -'9552ceac803aac6bd88f3b95de8dce4f314730962b2d1a598cbd0bb61017d8d8', -'c9f0eac85cdbf0ce00ed19197f938084f36f81a45ed6470931287c0471e64272', -'fc8c9b7720e4671de42c4473a603c4ff7ef49e579b70bde01431b1a1e905cbd0', -'f92eda195323a5938bc3514116fa4f05dac695c785a20be8f8afa8e967901769', -'36671b6c0a92eec53a0bbf98c1e7f1e9734ea2e9185d0d5038a8c4a157ba876f', -'ce6b04307b81dacce56cb3c87972ecdd28bba40e52b9d1efeea5651f52fe691f', -'ea4a8c27e68bbb4f70121a2c7b1877cdff8737e014e9bad1abbe83b0c3997b1c', -'5ef8953f395c841e27ddc1fe3ca0d79331c8189807cec5ed0ff724da5e08cefe', -'bcd37032ad64ce978586cfb1a65b3ec5bb7446eefada4149ce9d7a88b669ed7a', -'ff1e4deba577be3a1e9c9c31c61d305bc0aa13c10bc2ec6064057adc4a36c5f1', -'a8b67d1442fd65d4d05d3bcb6da74c7a59739787df08e120fd4d733e5f966aa7', -'c9eba770b629fd32d2180553cb96d8352dc5cb0bb652f900ffc1e9e29038f98f', -'ed1da7bbd10476dd0e84d0cefa6a457230c84bb4b31190b4ff4b58e25c398210', -'3aa16d6479d93b8bd0c4642856190ea0dc8777723b74089af58bd61b4700d8f2', -'bb47dea8df3aab2f16960e5ab33fa54c9c1bc239833f69fabba64a7b099fc688', -'f2ee6e2778650b556ec5e5e6fc6127e31fe7976efd7b2401e7b36cc7ec260fd4', -'a2604f43af7a5b9f600d34e0c9a1b3829360d2ccbbe20de96a0c32f4a7d70e18', -'b55b22f981a3ffe3c8ccf0ef320f72cd4f228b74bd4bda73236a0c8f67478999', -'322f60f380573876b5391e77b1296640d97de56d6efcb21f83d6d010e0820165', -'45d44e43a04b4025456e2e6f265c5fca05245350e817b79b28fd97e3212f832c', -'4266ae72d5ee29b527b283d137f9f7552b926b21aec867158fc8256df08c6b54', -'f0e8db89dc4bb6f1d0afd375a7ce62a1d6a8d30bead1a9e7fc2bf0a307402209', -'3cd8260017004591c8f66263f266f969ced86b858f2e3b43533d349f5f6d4167', -'e79b02d8eb1e72278d5d23db1ae4dd779bd834e4de15119a05f37fa849662277', -'8a9i0dc410bbd5404421af830def2b74e2baf8af566524ef018f0a6f45443538d', -'f47160e6901aa364a49a122c37591bd6bfc3091931931c66a87cd8002857c120', -'41284ecc6d052cb2e2674a9e78058a402a201290d8e5a0912cea571f59289ad8', -'4d328859872d13930f86cd367c2c4879efe0d13114aa233cf8fce3e42274ff92' } +goodblockset = {} + +goodtxset = {} def retryRequest(tempserverlist, apicall): @@ -872,7 +44,7 @@ def retryRequest(tempserverlist, apicall): def multiRequest(apicall, net): - testserverlist = ['http://0.0.0.0:9000/', 'https://testnet-flosight.duckdns.org/', 'https://testnet.flocha.in/'] + testserverlist = ['http://0.0.0.0:8495/'] mainserverlist = ['https://flosight.duckdns.org/','http://0.0.0.0:9495/'] if net == 'mainnet': return retryRequest(mainserverlist, apicall) @@ -904,12 +76,8 @@ def processBlock(blockindex): acceptedTxList = [] # Scan every transaction logger.info("Before tx loop") - #pdb.set_trace() - counter = 0 - #pdb.set_trace() + counter = 0 for transaction in blockinfo["tx"]: - if blockindex < 4365011 and (transaction not in goodtxset): - continue counter = counter + 1 logger.info(f"Transaction {counter} {transaction}") #transaction_data = multiRequest(f"tx/{transaction}", config['DEFAULT']['NET']) @@ -920,14 +88,14 @@ def processBlock(blockindex): # logger.info("The API has passed the Block height test but failed transaction_data['floData'] test. transaction_data response from the API is logged below") # logger.info(f"{transaction_data}") - #if current_index == -1: + current_index = -1 while(current_index == -1): transaction_data = multiRequest(f"tx/{transaction}", config['DEFAULT']['NET']) try: text = transaction_data["floData"] - text = text.replace("\n", " \n ") + text = text.replace("\n", " \n ") current_index = 2 except: logger.info("The API has passed the Block height test but failed transaction_data['floData'] test") @@ -940,6 +108,8 @@ def processBlock(blockindex): # todo Rule 9 - Reject all noise transactions. Further rules are in parsing.py returnval = None + if(transaction in ["77c92bcf40a86cd2e2ba9fa678249a9f4753c98c8038b1b9e9a74008f0ec93e8","b3e5c6343e3fc989e1d563b703573a21e0d409eb2ca7a9392dff7c7c522b1551", "fec1be48683c8f9a7d22e9fc6afddb68a641a364a26716fdfeaf3c21f27346c0"]): + pdb.set_trace() parsed_data = parsing.parse_flodata(text, blockinfo, config['DEFAULT']['NET']) if parsed_data['type'] != 'noise': logger.info(f"Processing transaction {transaction}") @@ -969,6 +139,8 @@ def processBlock(blockindex): # Check smartContracts which will be triggered locally, and not by the contract committee checkLocaltriggerContracts(blockinfo) + # Check if any deposits have to be returned + checkReturnDeposits(blockinfo) def processApiBlock(blockhash): @@ -1453,6 +625,10 @@ def checkLocaltriggerContracts(blockinfo): return +def checkReturnDeposits(blockinfo): + pass + + def processTransaction(transaction_data, parsed_data): # Do the necessary checks for the inputs and outputs # todo Rule 38 - Here we are doing FLO processing. We attach asset amounts to a FLO address, so every FLO address @@ -1465,6 +641,7 @@ def processTransaction(transaction_data, parsed_data): # originting. To ensure consistency, we will have to check that even if there are more than one vins in a transaction, there should be # excatly one FLO address on the originating side and that FLO address should be the owner of the asset tokens being transferred + # Create vinlist and outputlist vinlist = [] querylist = [] @@ -1491,16 +668,14 @@ def processTransaction(transaction_data, parsed_data): temp = item[0] continue if item[0] != temp: - logger.info( - f"System has found more than one address as part of vin. Transaction {transaction_data['txid']} is rejected") + logger.info(f"System has found more than one address as part of vin. Transaction {transaction_data['txid']} is rejected") return 0 inputlist = [vinlist[0][0], totalinputval] # todo Rule 42 - If the number of vout is more than 2, reject the transaction if len(transaction_data["vout"]) > 2: - logger.info( - f"System has found more than 2 address as part of vout. Transaction {transaction_data['txid']} is rejected") + logger.info(f"System has found more than 2 address as part of vout. Transaction {transaction_data['txid']} is rejected") return 0 # todo Rule 43 - A transaction accepted by the system has two vouts, 1. The FLO address of the receiver @@ -1527,10 +702,8 @@ def processTransaction(transaction_data, parsed_data): else: outputlist = outputlist[0] - logger.info( - f"Input address list : {inputlist}") - logger.info( - f"Output address list : {outputlist}") + logger.info(f"Input address list : {inputlist}") + logger.info(f"Output address list : {outputlist}") # All FLO checks completed at this point. # Semantic rules for parsed data begins @@ -1614,27 +787,21 @@ def processTransaction(transaction_data, parsed_data): # 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 os.path.isfile(f"./smartContracts/{parsed_data['contractName']}-{outputlist[0]}.db"): - # Check if the transaction hash already exists in the contract db (Safety check) - 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() - participantAdd_txhash = connection.execute( - 'select participantAddress, transactionHash from contractparticipants').fetchall() + participantAdd_txhash = connection.execute('select participantAddress, transactionHash from contractparticipants').fetchall() participantAdd_txhash_T = list(zip(*participantAdd_txhash)) if len(participantAdd_txhash) != 0 and transaction_data['txid'] in list(participantAdd_txhash_T[1]): - logger.warning( - f"Transaction {transaction_data['txid']} rejected as it already exists in the Smart Contract db. This is unusual, please check your code") - pushData_SSEapi( - f"Error | Transaction {transaction_data['txid']} rejected as it already exists in the Smart Contract db. This is unusual, please check your code") + logger.warning(f"Transaction {transaction_data['txid']} rejected as it already exists in the Smart Contract db. This is unusual, please check your code") + pushData_SSEapi(f"Error | Transaction {transaction_data['txid']} rejected as it already exists in the Smart Contract db. This is unusual, please check your code") return 0 # if contractAddress was passed, then check if it matches the output address of this contract if 'contractAddress' in parsed_data: if parsed_data['contractAddress'] != outputlist[0]: - logger.info( - f"Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}") + logger.info(f"Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}") # Store transfer as part of RejectedContractTransactionHistory engine = create_engine( f"sqlite:///system.db", @@ -1642,8 +809,7 @@ def processTransaction(transaction_data, parsed_data): SystemBase.metadata.create_all(bind=engine) session = sessionmaker(bind=engine)() blockchainReference = neturl + 'tx/' + transaction_data['txid'] - session.add( - RejectedContractTransactionHistory(transactionType='participation', + session.add(RejectedContractTransactionHistory(transactionType='participation', contractName=parsed_data['contractName'], contractAddress=outputlist[0], sourceFloAddress=inputadd, @@ -1663,22 +829,18 @@ def processTransaction(transaction_data, parsed_data): url = 'https://ranchimallflo.duckdns.org/' headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} - '''r = requests.post(url, json={ - 'message': f"Error | Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}"}, + '''r = requests.post(url, json={'message': f"Error | Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}"}, headers=headers)''' # Pass information to SSE channel - pushData_SSEapi( - 'Error| Mismatch in contract address specified in flodata and the output address of the transaction {}'.format( + pushData_SSEapi('Error| Mismatch in contract address specified in flodata and the output address of the transaction {}'.format( transaction_data['txid'])) return 0 # check the status of the contract engine = create_engine('sqlite:///system.db', echo=True) connection = engine.connect() - contractStatus = connection.execute( - f"select status from activecontracts where contractName=='{parsed_data['contractName']}' and contractAddress='{outputlist[0]}'").fetchall()[ - 0][0] + contractStatus = connection.execute(f"select status from activecontracts where contractName=='{parsed_data['contractName']}' and contractAddress='{outputlist[0]}'").fetchall()[0][0] connection.close() contractList = [] @@ -1770,11 +932,9 @@ def processTransaction(transaction_data, parsed_data): return 0 # pull out the contract structure into a dictionary - 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() - attributevaluepair = connection.execute( - "select attribute, value from contractstructure where attribute != 'contractName' and attribute != 'flodata' and attribute != 'contractAddress'").fetchall() + attributevaluepair = connection.execute("select attribute, value from contractstructure where attribute != 'contractName' and attribute != 'flodata' and attribute != 'contractAddress'").fetchall() contractStructure = {} conditionDict = {} counter = 0 @@ -2013,7 +1173,6 @@ def processTransaction(transaction_data, parsed_data): transactionHash=transaction_data['txid'], blockchainReference=blockchainReference, jsonData=json.dumps(transaction_data), - parsedFloData=json.dumps(parsed_data) )) @@ -2249,8 +1408,7 @@ def processTransaction(transaction_data, parsed_data): return 0 else: - logger.info( - f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {outputlist[0]} doesnt exist") + logger.info(f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {outputlist[0]} doesnt exist") # Store transfer as part of RejectedContractTransactionHistory engine = create_engine( f"sqlite:///system.db", @@ -2258,8 +1416,7 @@ def processTransaction(transaction_data, parsed_data): SystemBase.metadata.create_all(bind=engine) session = sessionmaker(bind=engine)() blockchainReference = neturl + 'tx/' + transaction_data['txid'] - session.add( - RejectedContractTransactionHistory(transactionType='participation', + session.add(RejectedContractTransactionHistory(transactionType='participation', contractName=parsed_data['contractName'], contractAddress=outputlist[0], sourceFloAddress=inputadd, @@ -2357,14 +1514,10 @@ def processTransaction(transaction_data, parsed_data): logger.info("Smart contract is of the type one-time-event") # either userchoice or payeeAddress condition should be present. Check for it - if 'userchoices' not in parsed_data['contractConditions'] and 'payeeAddress' not in parsed_data[ - 'contractConditions']: - logger.info( - f"Either userchoice or payeeAddress should be part of the Contract conditions.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected") + if 'userchoices' not in parsed_data['contractConditions'] and 'payeeAddress' not in parsed_data['contractConditions']: + logger.info(f"Either userchoice or payeeAddress should be part of the Contract conditions.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected") # Store transfer as part of RejectedContractTransactionHistory - engine = create_engine( - f"sqlite:///system.db", - echo=True) + engine = create_engine(f"sqlite:///system.db", echo=True) SystemBase.metadata.create_all(bind=engine) session = sessionmaker(bind=engine)() blockchainReference = neturl + 'tx/' + transaction_data['txid'] @@ -2390,8 +1543,7 @@ def processTransaction(transaction_data, parsed_data): return 0 # userchoice and payeeAddress conditions cannot come together. Check for it - if 'userchoices' in parsed_data['contractConditions'] and 'payeeAddress' in parsed_data[ - 'contractConditions']: + if 'userchoices' in parsed_data['contractConditions'] and 'payeeAddress' in parsed_data['contractConditions']: logger.info( f"Both userchoice and payeeAddress provided as part of the Contract conditions.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected") # Store transfer as part of RejectedContractTransactionHistory @@ -2566,9 +1718,166 @@ def processTransaction(transaction_data, parsed_data): 'Error | Contract Incorporation rejected as address in Flodata and input address are different at transaction {}'.format( transaction_data['txid'])) return 0 + + if parsed_data['contractType'] == 'continuous-event': + logger.debug("Smart contract is of the type continuous-event") + # Add checks to reject the creation of contract + if parsed_data['contractAddress'] == inputadd: + dbName = '{}-{}'.format(parsed_data['contractName'], parsed_data['contractAddress']) + engine = create_engine('sqlite:///smartContracts/{}.db'.format(dbName), echo=True) + ContinuosContractBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + session.add(ContractStructure1(attribute='contractType', index=0, value=parsed_data['contractType'])) + session.add(ContractStructure1(attribute='contractName', index=0, value=parsed_data['contractName'])) + session.add(ContractStructure1(attribute='contractAddress', index=0, value=parsed_data['contractAddress'])) + session.add(ContractStructure1(attribute='flodata', index=0, value=parsed_data['flodata'])) + if 'subtype' in parsed_data['contractConditions']: + # todo: Check if the both the tokens mentioned exist if its a token swap + if (parsed_data['contractConditions']['subtype'] == 'tokenswap') and (os.path.isfile(f"./tokens/{parsed_data['contractConditions']['accepting_token'].split('#')[0]}.db")) and (os.path.isfile(f"./tokens/{parsed_data['contractConditions']['selling_token'].split('#')[0]}.db")): + #if (parsed_data['contractConditions']['subtype'] == 'tokenswap'): + if parsed_data['contractConditions']['priceType'] in ['predetermined','determined']: + session.add(ContractStructure1(attribute='subtype', index=0, value=parsed_data['contractConditions']['subtype'])) + session.add(ContractStructure1(attribute='accepting_token', index=0, value=parsed_data['contractConditions']['accepting_token'])) + session.add(ContractStructure1(attribute='selling_token', index=0, value=parsed_data['contractConditions']['selling_token'])) + # determine price + session.add(ContractStructure1(attribute='priceType', index=0, value=parsed_data['contractConditions']['priceType'])) + session.add(ContractStructure1(attribute='price', index=0, value=parsed_data['contractConditions']['price'])) + + + # Store transfer as part of ContractTransactionHistory + blockchainReference = neturl + 'tx/' + transaction_data['txid'] + session.add(ContractTransactionHistory1(transactionType='incorporation', sourceFloAddress=inputadd, + destFloAddress=outputlist[0], + transferAmount=None, + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + time=transaction_data['blocktime'], + transactionHash=transaction_data['txid'], + blockchainReference=blockchainReference, + jsonData=json.dumps( + transaction_data), + parsedFloData=json.dumps( + parsed_data) + )) + session.commit() + session.close() + + # add Smart Contract name in token contract association + accepting_sending_tokenlist = [parsed_data['contractConditions']['accepting_token'], parsed_data['contractConditions']['selling_token']] + for token_name in accepting_sending_tokenlist: + token_name = token_name.split('#')[0] + engine = create_engine(f"sqlite:///tokens/{token_name}.db", echo=True) + Base.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + session.add(TokenContractAssociation(tokenIdentification=token_name, + contractName=parsed_data['contractName'], + contractAddress=parsed_data['contractAddress'], + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + time=transaction_data['blocktime'], + transactionHash=transaction_data['txid'], + blockchainReference=blockchainReference, + jsonData=json.dumps(transaction_data), + transactionType=parsed_data['type'], + parsedFloData=json.dumps(parsed_data))) + 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', + tokenIdentification=str(accepting_sending_tokenlist), + contractType=parsed_data['contractType'], + transactionHash=transaction_data['txid'], + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + incorporationDate=transaction_data['blocktime'])) + session.commit() + + # todo - Add a condition for rejected contract transaction on the else loop for this condition + session.add(ContractAddressMapping(address=inputadd, addressType='incorporation', + tokenAmount=None, + contractName=parsed_data['contractName'], + contractAddress=inputadd, + transactionHash=transaction_data['txid'], + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'])) + session.commit() + session.close() + + updateLatestTransaction(transaction_data, parsed_data) + + pushData_SSEapi('Contract | Contract incorporated at transaction {} with name {}-{}'.format(transaction_data['txid'], parsed_data['contractName'], parsed_data['contractAddress'])) + return 1 + + '''else if (parsed_data['contractConditions']['subtype'] == 'bitbonds'): + # Check if both the tokens mentioned in the bond exist + pass + ''' + else: + logger.info(f"priceType is not part of accepted parameters for a continuos event contract of the type token swap.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected") + # Store transfer as part of RejectedContractTransactionHistory + engine = create_engine(f"sqlite:///system.db", echo=True) + SystemBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + blockchainReference = neturl + 'tx/' + transaction_data['txid'] + session.add(RejectedContractTransactionHistory(transactionType='incorporation', + contractName=parsed_data['contractName'], + contractAddress=outputlist[0], + sourceFloAddress=inputadd, + destFloAddress=outputlist[0], + transferAmount=None, + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + time=transaction_data['blocktime'], + transactionHash=transaction_data['txid'], + blockchainReference=blockchainReference, + jsonData=json.dumps( + transaction_data), + rejectComment=f"priceType is not part of accepted parameters for a continuos event contract of the type token swap.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected", + parsedFloData=json.dumps( + parsed_data) + )) + session.commit() + session.close() + return 0 + + else: + logger.info(f"No subtype provided || mentioned tokens do not exist for the Contract of type continuos event.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected") + # Store transfer as part of RejectedContractTransactionHistory + engine = create_engine(f"sqlite:///system.db", echo=True) + SystemBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + blockchainReference = neturl + 'tx/' + transaction_data['txid'] + session.add(RejectedContractTransactionHistory(transactionType='incorporation', + contractName=parsed_data['contractName'], + contractAddress=outputlist[0], + sourceFloAddress=inputadd, + destFloAddress=outputlist[0], + transferAmount=None, + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + time=transaction_data['blocktime'], + transactionHash=transaction_data['txid'], + blockchainReference=blockchainReference, + jsonData=json.dumps( + transaction_data), + rejectComment=f"No subtype provided for the Contract of type continuos event.\nSmart contract incorporation on transaction {transaction_data['txid']} rejected", + parsedFloData=json.dumps( + parsed_data) + )) + session.commit() + session.close() + return 0 + + session.commit() + session.close() + else: - logger.info( - f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {parsed_data['contractAddress']} already exists") + logger.info(f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {parsed_data['contractAddress']} already exists") # Store transfer as part of RejectedContractTransactionHistory engine = create_engine(f"sqlite:///system.db", echo=True) SystemBase.metadata.create_all(bind=engine) @@ -2586,7 +1895,6 @@ def processTransaction(transaction_data, parsed_data): blockchainReference=blockchainReference, jsonData=json.dumps(transaction_data), rejectComment=f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {parsed_data['contractAddress']} already exists", - parsedFloData=json.dumps(parsed_data) )) session.commit() @@ -3058,6 +2366,138 @@ def processTransaction(transaction_data, parsed_data): f"Transaction {transaction_data['txid']} rejected as input address, {inputlist[0]}, is not part of the committee address list") return 0 + elif parsed_data['type'] == 'smartContractDeposit': + if os.path.isfile(f"./smartContracts/{parsed_data['contractName']}-{outputlist[0]}.db"): + # Check if the transaction hash already exists in the contract db (Safety check) + engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True) + connection = engine.connect() + participantAdd_txhash = connection.execute('select participantAddress, transactionHash from contractparticipants').fetchall() + participantAdd_txhash_T = list(zip(*participantAdd_txhash)) + + if len(participantAdd_txhash) != 0 and transaction_data['txid'] in list(participantAdd_txhash_T[1]): + logger.warning(f"Transaction {transaction_data['txid']} rejected as it already exists in the Smart Contract db. This is unusual, please check your code") + pushData_SSEapi(f"Error | Transaction {transaction_data['txid']} rejected as it already exists in the Smart Contract db. This is unusual, please check your code") + return 0 + + # if contractAddress was passed, then check if it matches the output address of this contract + if 'contractAddress' in parsed_data: + if parsed_data['contractAddress'] != outputlist[0]: + logger.info(f"Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}") + # Store transfer as part of RejectedContractTransactionHistory + engine = create_engine(f"sqlite:///system.db", echo=True) + SystemBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + blockchainReference = neturl + 'tx/' + transaction_data['txid'] + session.add(RejectedContractTransactionHistory(transactionType='participation', + contractName=parsed_data['contractName'], + contractAddress=outputlist[0], + sourceFloAddress=inputadd, + destFloAddress=outputlist[0], + transferAmount=None, + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + time=transaction_data['blocktime'], + transactionHash=transaction_data['txid'], + blockchainReference=blockchainReference, + jsonData=json.dumps(transaction_data), + rejectComment=f"Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}", + parsedFloData=json.dumps(parsed_data))) + session.commit() + session.close() + + url = 'https://ranchimallflo.duckdns.org/' + headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} + '''r = requests.post(url, json={ + 'message': f"Error | Contract participation at transaction {transaction_data['txid']} rejected as contractAddress specified in flodata, {parsed_data['contractAddress']}, doesnt not match with transaction's output address {outputlist[0]}"}, + headers=headers)''' + + # Pass information to SSE channel + pushData_SSEapi('Error| Mismatch in contract address specified in flodata and the output address of the transaction {}'.format(transaction_data['txid'])) + return 0 + + # pull out the contract structure into a dictionary + engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True) + connection = engine.connect() + attributevaluepair = connection.execute("select attribute, value from contractstructure where attribute != 'contractName' and attribute != 'flodata' and attribute != 'contractAddress'").fetchall() + contractStructure = {} + conditionDict = {} + counter = 0 + for item in attributevaluepair: + if list(item)[0] == 'exitconditions': + conditionDict[counter] = list(item)[1] + counter = counter + 1 + else: + contractStructure[list(item)[0]] = list(item)[1] + if len(conditionDict) > 0: + contractStructure['exitconditions'] = conditionDict + del counter, conditionDict + + + # Push the deposit trasaction into deposit database contract database + engine = create_engine('sqlite:///smartContracts/{}-{}.db'.format(parsed_data['contractName'], outputlist[0]), echo=True) + ContinuosContractBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + blockchainReference = neturl + 'tx/' + transaction_data['txid'] + session.add(ContractDeposits1(depositorAddress = inputadd, + depositAmount = parsed_data['depositAmount'], + expiryTime = parsed_data['depositConditions']['expiryTime'], + transactionHash = transaction_data['txid'], + blockNumber = transaction_data['blockheight'], + blockHash = transaction_data['blockhash'] + )) + session.add(ContractTransactionHistory1(transactionType = 'smartContractDeposit', + transactionSubType = None, + sourceFloAddress = inputadd, + destFloAddress = outputlist[0], + transferAmount = parsed_data['depositAmount'], + blockNumber = transaction_data['blockheight'], + blockHash = transaction_data['blockhash'], + time = transaction_data['blocktime'], + transactionHash = transaction_data['txid'], + blockchainReference = blockchainReference, + jsonData = json.dumps(transaction_data), + parsedFloData = json.dumps(parsed_data) + )) + session.commit() + session.close() + pushData_SSEapi(f"Error | Transaction {transaction_data['txid']} rejected as maximum subscription amount has been reached for the Smart contract named {parsed_data['contractName']} at the address {outputlist[0]}") + return 0 + + + else: + logger.info(f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {outputlist[0]} doesnt exist") + # Store transfer as part of RejectedContractTransactionHistory + engine = create_engine(f"sqlite:///system.db",echo=True) + SystemBase.metadata.create_all(bind=engine) + session = sessionmaker(bind=engine)() + blockchainReference = neturl + 'tx/' + transaction_data['txid'] + session.add(RejectedContractTransactionHistory(transactionType='smartContractDeposit', + contractName=parsed_data['contractName'], + contractAddress=outputlist[0], + sourceFloAddress=inputadd, + destFloAddress=outputlist[0], + transferAmount=None, + blockNumber=transaction_data['blockheight'], + blockHash=transaction_data['blockhash'], + time=transaction_data['blocktime'], + transactionHash=transaction_data['txid'], + blockchainReference=blockchainReference, + jsonData=json.dumps(transaction_data), + rejectComment=f"Transaction {transaction_data['txid']} rejected as a Smart Contract with the name {parsed_data['contractName']} at address {outputlist[0]} doesnt exist", + + parsedFloData=json.dumps(parsed_data) + )) + session.commit() + session.close() + + url = 'https://ranchimallflo.duckdns.org/' + headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} + '''r = requests.post(url, json={'message': f"Error | Contract transaction {transaction_data['txid']} rejected as a smartcontract with same name {parsed_data['contractName']}-{parsed_data['contractAddress']} dosent exist "}, headers=headers)''' + return 0 + + + ''' {'type': 'smartContractDeposit', 'tokenIdentification': hashList[0][:-1], 'contractName': atList[0][:-1], 'flodata': string, 'depositConditions': deposit_conditions} ''' + def scanBlockchain(): # Read start block no @@ -3087,13 +2527,7 @@ def scanBlockchain(): break for blockindex in range(startblock, current_index): - if blockindex < 4365011: - if blockindex in goodblockset: - processBlock(blockindex) - else: - logger.info(f"Skipping block {blockindex}") - else: - processBlock(blockindex) + processBlock(blockindex) # At this point the script has updated to the latest block # Now we connect to flosight's websocket API to get information about the latest blocks @@ -3145,7 +2579,7 @@ if config['DEFAULT']['NET'] == 'mainnet': neturl = 'http://0.0.0.0:9495/' localapi = config['DEFAULT']['FLO_CLI_PATH'] elif config['DEFAULT']['NET'] == 'testnet': - neturl = 'https://testnet-flosight.duckdns.org/' + neturl = 'http://0.0.0.0:8495/' localapi = '{} --testnet'.format(config['DEFAULT']['FLO_CLI_PATH']) else: logger.error( @@ -3185,7 +2619,7 @@ if args.reset == 1: def switchNeturl(currentneturl): - mainserverlist = ['http://0.0.0.0:9495/'] + mainserverlist = ['http://0.0.0.0:8495/'] neturlindex = mainserverlist.index(currentneturl) if neturlindex+1 >= len(mainserverlist): return mainserverlist[neturlindex+1 - len(mainserverlist)] @@ -3223,7 +2657,7 @@ scanBlockchain() # Now we connect to flosight's websocket API to get information about the latest blocks # Neturl is the URL for Flosight API whose websocket endpoint is being connected to -neturl = 'https://flosight.duckdns.org/' +neturl = 'https://testnet-flosight.duckdns.org/' sio = socketio.Client() # Connect to a websocket endpoint and wait for further events reconnectWebsocket(sio) @@ -3257,5 +2691,4 @@ def connect_error(): def on_block(data): logger.info('New block received') logger.info(str(data)) - processApiBlock(data) - + processApiBlock(data) \ No newline at end of file