denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
98.28k stars 5.41k forks source link

Userland function for setting the random seed #17782

Open tmcw opened 1 year ago

tmcw commented 1 year ago

This might be a little bit niche of a need! But, branching off of https://github.com/denoland/deno/issues/2322, my usecase is: running untrusted user code, using a Deno worker with limited permissions. I'd like to aim for code to be replayable, so capturing as many parts of non-determinism as possible.

So, non-determinism in this case is mainly interacting with the outside world, and using Math.random. It'd be nice if Math.random was controllable not only with a CLI flag on startup, but also by something like:

An item in the deno object?

const worker = new Worker(new URL("./worker.ts", import.meta.url).href, {
  type: "module",
  deno: {
    // Here?
    seed: 10
  },
});

Or a method in userspace?

Deno.setRandomSeed(10);

Either would be great, and I'm not trying to propose exactly any API - just the idea that it'd be nice to control the random seed at such a low level without needing to restart a process.

ry commented 1 year ago

I’d be open to adding either. Which one fits your use case better?

tmcw commented 1 year ago

That's awesome! Deno.setRandomSeed (or something like it) would probably be the nicer general solution because it'd conceivably be runnable without using a worker.

bartlomieju commented 1 year ago

That's awesome! Deno.setRandomSeed (or something like it) would probably be the nicer general solution because it'd conceivably be runnable without using a worker.

I'd like to push back on this idea. If you want to run untrusted code then what will happen if user code will call Deno.setRandomSeed() again? Will it overwrite the seed or throw the error?

Then there's the actual implementation - currently seeding an RNG is done via a V8 flag. AFAIK passing a seed causes all workers to use the same seed. We would need to figure out how to seed each instance of JsRuntime its own seed value.

kigiri commented 2 weeks ago

I'm in the exact same camp, I believe having a dynamic call is dangerous would require an extra permission for sure, for my use case, being able to pass it to the worker is enough:

const worker = new Worker(new URL("./worker.ts", import.meta.url).href, {
  type: "module",
  deno: {
    // Here?
    seed: 10
  },
});

like so