Skip to content

feat(Vm): add deterministic shuffling vm.shuffle(salt) #10664

Closed
@0xClandestine

Description

@0xClandestine

Component

Forge

Describe the feature you would like

Thanks again for adding vm.sort() and vm.shuffle()!

One use case that’s come up frequently: I often work with two corresponding arrays (like strategies[i] and balances[i]) and need to shuffle them in sync to maintain their index alignment. Currently, there’s no built-in way to ensure two shuffles apply the same permutation.

It would be incredibly useful if vm.shuffle() accepted an optional salt parameter for deterministic shuffling. That way, we could do something like:

uint256 salt = vm.randomUint();
vm.shuffle(strategies, salt);
vm.shuffle(balances, salt);

This would make it much easier to preserve relationships across parallel arrays during randomized testing.

Additional context

#10171

Activity

0xalpharush

0xalpharush commented on Jun 1, 2025

@0xalpharush
Contributor

You can add an arg to make a test a fuzz test and use that as the seed

0xClandestine

0xClandestine commented on Jun 2, 2025

@0xClandestine
Author

You can add an arg to make a test a fuzz test and use that as the seed

Given vm.shuffle() does not currently accept a salt parameter, that's not possible.

added
first issueA good way to start contributing
C-forgeCommand: forge
and removed
T-needs-triageType: this issue needs to be labelled
on Jun 3, 2025
nguyenethan01

nguyenethan01 commented on Jun 3, 2025

@nguyenethan01
Contributor

Anyone taking this yet? Would be happy to take a look

Another-DevX

Another-DevX commented on Jun 4, 2025

@Another-DevX
Contributor

Gm, I'm working on this!

DaniPopes

DaniPopes commented on Jun 4, 2025

@DaniPopes
Member

I don't think we should have a seed parameter for each individual rng function, but it could be set globally/for the current test with a setSeed or similar

As mentioned the seed will be the fuzz/invariant one if the test is one of those; we could also add a global test seed config

I think I prefer the config since it can be specified inline which would fulfill the same purpose as a cheatcode

cc @grandizzy @zerosnacks

Another-DevX

Another-DevX commented on Jun 4, 2025

@Another-DevX
Contributor

Gm, @DaniPopes
So the focus of this issue would then be to implement a cheatcode that updates the RNG seed in CheatsConfig, right?

Do you have any suggestions or preferences for how to approach this?
I'm thinking of exposing something like vm.setSeed(uint256) that internally updates the config, similar to how other cheatcodes modify global state.

Another-DevX

Another-DevX commented on Jun 4, 2025

@Another-DevX
Contributor

I just added a method to overwrite the cheatsConfig seed via the new cheat vm.setSeed(uint256). Hopefully that’s enough for rng() to return an instance using the provided seed. Could you review it and let me know what I should fix or improve? This is my first contribution to Foundry 😅.

I also wrote a test under testdata, but I’m a bit in the dark on how to run only that one with the forge binary. Sorry if that’s a trivial question!

0xClandestine

0xClandestine commented on Jun 4, 2025

@0xClandestine
Author

I don't think we should have a seed parameter for each individual rng function, but it could be set globally/for the current test with a setSeed or similar

As mentioned the seed will be the fuzz/invariant one if the test is one of those; we could also add a global test seed config

I think I prefer the config since it can be specified inline which would fulfill the same purpose as a cheatcode

cc @grandizzy @zerosnacks

Thanks for the input! I agree that having a salted alias (like vm.shuffle(array,salt) might not be the best solution.

However, relying solely on a global config setting for the RNG seed wouldn’t solve the issue I'm facing. Having vm.setSeed(seed) would allow precise control while keeping the interface simple and composable.

My above example would become:

uint256 seed = vm.randomUint();

vm.setSeed(seed);
vm.shuffle(strategies);

// Ensure shuffled `balances` align with `strategies`.
vm.setSeed(seed);
vm.shuffle(balances);

May also be nice to fetch the current fuzz seed via vm.getSeed() or something, so you could use the current randomness twice.

moved this from Backlog to Done in Foundryon Jun 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @grandizzy@nguyenethan01@DaniPopes@Another-DevX@0xalpharush

      Issue actions

        feat(`Vm`): add deterministic shuffling `vm.shuffle(salt)` · Issue #10664 · foundry-rs/foundry