For now, the localhost:3001 is the same as the node requesting it, eventually will be many nodes + a balancer.
Given this code, is there a flaw where we will be reallocating addresseses too quickly?
The part:
        try {
            let new_balance = await getBalance(publicKey);
            await transferFunds(secretKey, nextNodeAddress, new_balance);
            console.log(`Next node transfer complete...`);
        } catch (error) {
            console.log(`Transaction error, retrying... ${error}`);
            done(new Error("Transaction error, retrying..."));
            return;
        }
is getting a nextNodeAddress, but not giving it back in case of a failure?
full code:
app.use('/get_wallet_info', async (req, res) => {
    try {
        // Atomically pop a wallet from the list in Redis
        const walletData = await redis.lpop('wallet_pool');

        if (!walletData) {
            return res.status(500).json({ success: false, message: 'No wallets available' });
        }

        const { publicKey, secretKey } = JSON.parse(walletData);

        const { finalDestinationAddress, currentHop, minHops, maxHops } = req.body;
        // Assuming relayQueue is already defined and used for queuing tasks
        relayQueue.add({ publicKey, secretKey, finalDestinationAddress, currentHop, minHops, maxHops });
        
        res.json({ success: true, walletAddress: publicKey });
    } catch (error) {
        console.error('Error retrieving wallet:', error);
        res.status(500).send('Server error');
    }
});
const get_next_node = async (finalDestinationAddress: string, currentHop: number, minHops: number, maxHops: number): Promise<string> => {
    const responseUrl = 'http://localhost:3001/get_wallet_info'; // URL of the next node's API endpoint
    try {
        const response = await axios.post<RelayNodeResponse>(responseUrl, {
            finalDestinationAddress,
            currentHop: currentHop + 1, // Increment currentHop
            minHops,
            maxHops
        });

        const data = response.data; // With Axios, no need to manually parse the JSON

        if (data.success && data.walletAddress) {
            return data.walletAddress; // Return the wallet address received from the node
        } else {
            throw new Error('Node did not return a wallet address.');
        }
    } catch (error) {
        console.error('Failed to get next node wallet address:', error);
        // Axios wraps the native error, so we check for response statusText this way
        throw new Error('Unknown Error');
    }
};

relayQueue.process(async (job, done) => {
    const { publicKey, secretKey, finalDestinationAddress, currentHop, minHops, maxHops } = job.data;
    
    let balance = await getBalance(publicKey);

    if(balance == 0){
        done(new Error("Not enough balance yet."));
        return;
    }

    if (balance <=  0.000005) {
        const walletData = JSON.stringify({ publicKey, secretKey });
        await redis.rpush('wallet_pool', walletData);

        console.log(`Wallet replenished to the pool.`);

        done();
        return;
    }

    // Calculate the transfer amount based on hop conditions
    let transferAmount = balance;
    if (currentHop < maxHops) {
        // If not yet at max hops, decide whether to transfer a portion to the final destination
        if (currentHop >= minHops) {
            const percentageToTransfer = Math.random() * (30 - 5) + 5; // Random between 20% and 30%
            const amountToFinal = balance * (percentageToTransfer / 100);
            transferAmount -= amountToFinal;

            console.log(`Transferring ${amountToFinal} to final destination: ${finalDestinationAddress}`);

            try {
                await transferFunds(secretKey, finalDestinationAddress, amountToFinal);
            } catch (error) {
                console.log(`Transaction error, retrying... ${error}`);
                done(new Error("Transaction error, retrying..."));
                return;
            }
        }
        
        console.log(`Trying next node transfer...`);

        const nextNodeAddress = await get_next_node(finalDestinationAddress, currentHop, minHops, maxHops);
        
        console.log(`Transferring ${transferAmount} to next node: ${nextNodeAddress}`);
        
        try {
            let new_balance = await getBalance(publicKey);
            await transferFunds(secretKey, nextNodeAddress, new_balance);
            console.log(`Next node transfer complete...`);
        } catch (error) {
            console.log(`Transaction error, retrying... ${error}`);
            done(new Error("Transaction error, retrying..."));
            return;
        }
        
        const walletData = JSON.stringify({ publicKey, secretKey });
        await redis.rpush('wallet_pool', walletData);

        console.log(`Wallet replenished to the pool.`);

        done();
    } else {
        console.log(`Final hop. Transferring entire balance ${balance} to ${finalDestinationAddress}`);

        try {
            await transferFunds(secretKey, finalDestinationAddress, balance);
            console.log(`Final transfer complete...`);
        } catch (error) {
            console.log(`Transaction error, retrying... ${error}`);
            done(new Error("Transaction error, retrying..."));
            return;
        }
        
        const walletData = JSON.stringify({ publicKey, secretKey });
        await redis.rpush('wallet_pool', walletData);

        console.log(`Wallet replenished to the pool.`);

        done();
    }
});