BlackElefant
BlackElefant

Reputation: 37

Python - Recursive Loop is stuck

I want to set up a recursive loop to iterate over different levels of a transaction tree until a predefined depth is reached. Example:

A transfers funds to B and C (depth 1)

       - B transfers funds to D and E (depth 2)
       - C transfers funds to F and G (depth 2)

etc.

To do so, I have set up the following function:

def traverse(target, depth):
    try:
        print('Starting analysis of parent address {}'.format(target))
        result=callAddress(target) 
        inner_transaction_targets=analyseTransaction(result)
        traversed_addresses=compileAddresses(compiled_receiver_addresses,inner_transaction_targets) #Compile list of start addresses
        if depth > 0:
            for inner in inner_transaction_targets:
                print('Starting analysis of child address {} at depth {}.'.format(inner,depth))  
                inner_transaction_targets=inner_transaction_targets.pop(0)
                print(inner_transaction_targets)           
                return traverse(inner, depth-1)
                
        else:
            return traversed_addresses 
    except:
        print('Could not traverse.')

The functions callAdress, analyseTransaction and compileAdresses themselves should not be relevant to this problem. However to offer a brief description:

See here the other functions:

def callAddress(bitcoin_address):  #This function serves to retrieve the JSON respose from blockchain.info

    try:
        r = requests.get("https://blockchain.info/address/{}?format=json".format(bitcoin_address))
        unparsed=r.content
        parsed = json.loads(unparsed)
        return parsed

    except: #unparsed.status=="400":
        print ("Incorrect bitcoin address")
        

def compileAddresses(compiled_receiver_addresses,input_addr): #This function serves to add extracted transactions to a master list (compiled_receiver_addresses)
    try:
        compiled_receiver_addresses.append(input_addr)
        return compiled_receiver_addresses

    except:
        print('Failed to compile')

def analyseTransaction(response): #This function serves to extract the wallet addresses that the specified wallet has sent funds to (transaction targets)
    try:
        transaction_targets=[]
        wallet_transactions=response['txs']
        for txs_entry in wallet_transactions:
            print ("{:=^22}".format(""))
            print ("Checking outgoing transaction with Hash: {}".format(txs_entry['hash']))
            print ("Transaction occured at: {}".format(datetime.fromtimestamp(
                int(txs_entry['time']) ).strftime('%Y-%m-%d %H:%M:%S')))
            print ("{:=^22}".format(""))

            for out in txs_entry['out']:
                outbound_addr=out['addr']
                print ("In this transaction funds were sent to this wallet: {}".format(out['addr']))
                print ("Amount sent: {}".format(int(out['value']) * 10**-8))
                transaction_targets.append(outbound_addr)

        cleaned_transaction_targets = list(dict.fromkeys(transaction_targets))
        return cleaned_transaction_targets

    except:
        print('Dead End')

My issue is that the recursive loop keeps getting stuck on the first value, i.e. it is looping the very first value of "inner" over and over again instead of going down the list that is inner_transaction_targets I have tried to drop the very first value in this list by using inner_transaction_targets.pop(0) but to no effect.

How do I have to modify this function so that it does what I want?

Upvotes: 0

Views: 118

Answers (1)

Paulo Schau Guerra
Paulo Schau Guerra

Reputation: 631

Your code has some errors that are most likely hindering its successful completion, such as:

  1. The return is within a loop.
  2. The object returned is in fact a self-reference to the traverse() function.
  3. The .pop() method is not a good practice.

I would suggest you create a separate function that will return a single object for each inner transaction, much like what compile_addresses() does. You then add this new function into the for loop so that it iterates over the inner_transaction_targets and appends the results to a list. Finally, you return the list with all the results, indented aligned with the if statement, outside the for loop.

Upvotes: 1

Related Questions