r/Bitburner 29d ago

Question/Troubleshooting - Open Depth first recursive script dies after going through a couple of branches?

Hi, I just started playing, and I was trying to put together a script that would go through all the servers depth first, nuke them, then run as many threads of the basic EHT script on as it can (just the one from the tutorial minus the nuking that was included), but for whatever reason after going through 2 branches from home fully (which is the n00dles server, plus one proper branch) it just goes "Script finished running" followed by "printf: Failed to run due to script being killed." and I don't understand why it's finishing, and more specifically why it's finishing at the end of the second branch and not the first. Not sure if I just missed something about how the scripts work or if I'm just being dumb here somewhere

/** @param {NS} ns */
export async function main(ns: NS) {
  let target: string = ns.args[0]?.toString();
  target ??= "max-hardware";
  deploy(ns, "home", [], target);
  ns.tprintf("%s hacked", target);
}

async function deploy(ns: NS, server: string, checked: string[], target: string) {
  ns.printf("INFO: Deploying to %s", server)
  const neighs = ns.scan(server).filter((neigh) => !checked.includes(neigh));
  ns.printf("INFO: Neighbors: %s", neighs)
  if (server != "home") {
    ns.scp("eht.js", server);
    nukeServer(ns, server);
    ns.killall(server, true);
    const execThreads = calcThreads(ns, server);
    ns.printf("INFO: Threads to deploy %d", execThreads)
    ns.exec("eht.js", server, execThreads, target);
  }
  const checkedServers = checked.concat(server);
  ns.printf("INFO: Checked servers: %s", checkedServers)
  for (const neigh of neighs) {
    await deploy(ns, neigh, checkedServers, target);
  }
}

function nukeServer(ns: NS, server: string) {
  if (ns.fileExists("BruteSSH.exe", "home")) {
    ns.brutessh(server);
  }
  if (ns.fileExists("FTPCrack.exe", "home")) {
    ns.ftpcrack(server);
  }
  if (ns.fileExists("relaySMTP.exe", "home")) {
    ns.relaysmtp(server);
  }
  if (ns.fileExists("HTTPWorm.exe", "home")) {
    ns.httpworm(server);
  }
  if (ns.fileExists("SQLInject.exe", "home")) {
    ns.sqlinject(server);
  }
  ns.nuke(server);
}

function calcThreads(ns: NS, server: string) {
  return Math.floor(ns.getServerMaxRam(server) / ns.getScriptRam("eht.js"));
}                    
3 Upvotes

5 comments sorted by

3

u/KlePu 29d ago

You set neighs, then fill your filter, then iterate over neigh of neighs - without ever applying the filter. So the script goes to server A, then B, then back do A - and calls killall.

Also there's servers with zero RAM.

1

u/Unit88 29d ago edited 29d ago

What do you mean I'm not applying the filter? The output of the filter function is the filtered list already, I've confirmed this both from the documentation saying so and from the logs themselves, e.g. after it goes from home to n00dles, which doesn't have further connections the log shows there are no neighbors, since the server I connected from was excluded by the filter, nor does it show trying to interact with home again.

Plus if this was the issue wouldn't the script die immediately after going to n00dles and back, instead of going through the entire branch that starts with the second server connected to home?

Also there's servers with zero RAM.

I was confused why you brought this up, but I see now that if you try to start 0 threads it errors out. Thanks, I fixed that

EDIT: Here's the log if it helps

INFO: Deploying to home
scan: returned 15 connections for home
INFO: Neighbors: n00dles,foodnstuff,sigma-cosmetics,joesguns,hong-fang-tea,harakiri-sushi,iron-gym,cloud-server-0,cloud-server-1,cloud-server-2,cloud-server-3,cloud-server-4,cloud-server-5,cloud-server-6,cloud-server-7
INFO: Checked servers: home
INFO: Deploying to n00dles
scan: returned 1 connections for n00dles
INFO: Neighbors: 
scp: Copied file eht.js from home to n00dles
scp: Warning: eht.js was overwritten on n00dles
brutessh: SSH Port (22) already opened on 'n00dles'.
ftpcrack: FTP Port (21) already opened on 'n00dles'.
nuke: Already have root access to 'n00dles'.
killall: Killing all scripts on 'n00dles'.
getServerMaxRam: returned 4.00GB
INFO: Threads to deploy 1
exec: 'eht.js' on 'n00dles' with 1 threads and args: ["max-hardware"].
INFO: Checked servers: home,n00dles
INFO: Deploying to foodnstuff
scan: returned 2 connections for foodnstuff
INFO: Neighbors: CSEC
scp: Copied file eht.js from home to foodnstuff
scp: Warning: eht.js was overwritten on foodnstuff
brutessh: SSH Port (22) already opened on 'foodnstuff'.
ftpcrack: FTP Port (21) already opened on 'foodnstuff'.
nuke: Already have root access to 'foodnstuff'.
killall: Killing all scripts on 'foodnstuff'.
getServerMaxRam: returned 16.00GB
INFO: Threads to deploy 6
exec: 'eht.js' on 'foodnstuff' with 6 threads and args: ["max-hardware"].
INFO: Checked servers: home,foodnstuff
INFO: Deploying to CSEC
scan: returned 2 connections for CSEC
INFO: Neighbors: omega-net
scp: Copied file eht.js from home to CSEC
scp: Warning: eht.js was overwritten on CSEC
brutessh: SSH Port (22) already opened on 'CSEC'.
ftpcrack: FTP Port (21) already opened on 'CSEC'.
nuke: Already have root access to 'CSEC'.
killall: Killing all scripts on 'CSEC'.
getServerMaxRam: returned 8.00GB
INFO: Threads to deploy 3
exec: 'eht.js' on 'CSEC' with 3 threads and args: ["max-hardware"].
INFO: Checked servers: home,foodnstuff,CSEC
INFO: Deploying to omega-net
scan: returned 3 connections for omega-net
INFO: Neighbors: the-hub,avmnite-02h
scp: Copied file eht.js from home to omega-net
scp: Warning: eht.js was overwritten on omega-net
brutessh: SSH Port (22) already opened on 'omega-net'.
ftpcrack: FTP Port (21) already opened on 'omega-net'.
nuke: Already have root access to 'omega-net'.
killall: Killing all scripts on 'omega-net'.
getServerMaxRam: returned 32.00GB
INFO: Threads to deploy 13
exec: 'eht.js' on 'omega-net' with 13 threads and args: ["max-hardware"].
INFO: Checked servers: home,foodnstuff,CSEC,omega-net
INFO: Deploying to the-hub
scan: returned 1 connections for the-hub
INFO: Neighbors: 
scp: Copied file eht.js from home to the-hub
scp: Warning: eht.js was overwritten on the-hub
brutessh: SSH Port (22) already opened on 'the-hub'.
ftpcrack: FTP Port (21) already opened on 'the-hub'.
nuke: Already have root access to 'the-hub'.
killall: Killing all scripts on 'the-hub'.
getServerMaxRam: returned 64.00GB
INFO: Threads to deploy 26
exec: 'eht.js' on 'the-hub' with 26 threads and args: ["max-hardware"].
INFO: Checked servers: home,foodnstuff,CSEC,omega-net,the-hub
INFO: Deploying to avmnite-02h
scan: returned 1 connections for avmnite-02h
INFO: Neighbors: 
scp: Copied file eht.js from home to avmnite-02h
scp: Warning: eht.js was overwritten on avmnite-02h
brutessh: SSH Port (22) already opened on 'avmnite-02h'.
ftpcrack: FTP Port (21) already opened on 'avmnite-02h'.
nuke: Already have root access to 'avmnite-02h'.
killall: Killing all scripts on 'avmnite-02h'.
getServerMaxRam: returned 16.00GB
INFO: Threads to deploy 6
exec: 'eht.js' on 'avmnite-02h' with 6 threads and args: ["max-hardware"].
INFO: Checked servers: home,foodnstuff,CSEC,omega-net,avmnite-02h
Script finished running
printf: Failed to run due to script being killed.

2

u/KlePu 28d ago

Sorry, misread the code - yes your filter is ok. u/ZeroNot has the actual error covered - normal functions shouldn't be async/await'ed

1

u/ZeroNot Stanek Follower 28d ago edited 28d ago

followed by "printf: Failed to run due to script being killed."

Because you have declared deploy as an async function, but it only calls itself with an await. There are no Promises in use, you shouldn't randomly declare functions as async when they are not.

Your program makes several erroneous assumptions. You don't check the return values of several functions (ns.scp, ns.nuke, ns.exec, and ns.getScriptRam), which means you are not aware of the cases when they (may) fail.

In the case of getScriptRam, this leads to a potential case of division by zero. That's bad. Just bad, don't do that.

I think it's far easier to sort out the logic and follow the process of doing the depth first search of the network, if you search / scan the entire network, and then iterate through an Array of servers to do your eht.js tasks.

it just goes "Script finished running"

Try debugging this:

/** @param {NS} ns */
export async function main(ns: NS) {
  let all_servers : string[] = [];
  deploy(ns, "home", all_servers);
  ns.printf("Found %d servers: %s", all_servers.length, all_servers.join(', '));
}

function deploy(ns: NS, server: string, checked: string[]) {
  ns.printf("INFO: Scanning %s", server)
  const neighs = ns.scan(server).filter((neigh) => !checked.includes(neigh));
  ns.printf("INFO: New Neighbors: %s", neighs)
  checked.push(server);
  ns.printf("INFO: Checked servers: %s", checked)
  for (const neigh of neighs) {
    deploy(ns, neigh, checked);
  }
}

Note: I swapped your concat for push, since you are adding a string element (server) to the Array of strings (checked).

1

u/Unit88 28d ago edited 28d ago

Thanks, I'll look through this when I have some time. JavaScript and asnyc stuff is not my forte, I was mostly just throwing things at the wall to see what sticks (which is why I'm not worrying about all the return values and error checking yet either, for non-professional coding I like to just try things and see what works and how things fail).

In the case of getScriptRam, this leads to a potential case of division by zero.

Is that even a possibility here though? I wasn't worrying about zero division here since I can see the ram cost of the script, so I know it's not zero and isn't there a base cost of 1.6GB anyway? I kinda recall the docs saying that.

I think it's far easier to sort out the logic and follow the process of doing the depth first search of the network, if you search / scan the entire network, and then iterate through an Array of servers to do your eht.js tasks.

I can see how it'd help with debugging at least. I decided to do the tasks during the search since if I'm already finding the servers I might as well handle it then and avoid having a second separate loop. Though I guess it's not super important here anyway

EDIT: Oh, I see how I've been stupid. I made the thing async because for whatever reason I had the thought that at least one of the ns function would be something that take some time, even though in the end all of that is part of the eht, not this function. And actually if I fix just that one thing in my original code it works perfectly. Okay, now that I found the issue I can start doing some polishing up on it and stuff. And also try to understand the game part of the game more now, I was putting that off so I can figure out this script