Skip to content

Commit 308d5e2

Browse files
committed
nix: Add anvil state persistence for faster integration tests
Pin foundry to v1.4.0 and add state persistence options to anvil.nix: - state: path to state file (loads on start, saves periodically) - stateInterval: periodic state dump interval in seconds - preserveHistoricalStates: keep historical states for older block queries This allows anvil to persist blockchain state between test runs, skipping contract deployment on subsequent runs. The state is saved every 30 seconds to handle ungraceful shutdowns.
1 parent ebed5ff commit 308d5e2

3 files changed

Lines changed: 57 additions & 9 deletions

File tree

flake.lock

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
inputs = {
33
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
4-
foundry.url = "github:shazow/foundry.nix";
4+
foundry.url = "github:shazow/foundry.nix/b7adb89167832516589c899addcd25ca2a78dcfe";
55
fenix = {
66
url = "github:nix-community/fenix";
77
inputs.nixpkgs.follows = "nixpkgs";
@@ -198,6 +198,9 @@
198198
gasLimit = 100000000000;
199199
baseFee = 1;
200200
blockTime = 2;
201+
state = "./.data/integration/anvil/state.json";
202+
stateInterval = 30;
203+
preserveHistoricalStates = true;
201204
};
202205
};
203206
};

nix/anvil.nix

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,62 @@
3636
};
3737

3838
blockTime = lib.mkOption {
39-
type = lib.types.int;
40-
default = 2;
41-
description = "Block time for the genesis block";
39+
type = lib.types.nullOr lib.types.int;
40+
default = null;
41+
description = "Block time in seconds. Null means instant mining.";
42+
};
43+
44+
state = lib.mkOption {
45+
type = lib.types.nullOr lib.types.str;
46+
default = null;
47+
description = "Path to state file (loads on start, saves on exit)";
48+
};
49+
50+
stateInterval = lib.mkOption {
51+
type = lib.types.nullOr lib.types.int;
52+
default = null;
53+
description = "Interval in seconds to dump state to disk. Useful when graceful shutdown isn't guaranteed.";
54+
};
55+
56+
preserveHistoricalStates = lib.mkOption {
57+
type = lib.types.bool;
58+
default = false;
59+
description = "Preserve historical state snapshots when dumping. Enables RPC calls for older blocks after state reload.";
4260
};
4361
};
4462

4563
config = {
4664
outputs.settings.processes.${name} = {
47-
command = "${lib.getExe' config.package "anvil"} --gas-limit ${toString config.gasLimit} --base-fee ${toString config.baseFee} --block-time ${toString config.blockTime} --timestamp ${toString config.timestamp} --port ${toString config.port}";
65+
command = let
66+
stateDir =
67+
if config.state != null
68+
then builtins.dirOf config.state
69+
else null;
70+
mkdirCmd =
71+
if stateDir != null
72+
then "mkdir -p ${stateDir} && "
73+
else "";
74+
in
75+
mkdirCmd
76+
+ builtins.concatStringsSep " " (lib.filter (s: s != "") [
77+
"${lib.getExe' config.package "anvil"}"
78+
"--gas-limit ${toString config.gasLimit}"
79+
"--base-fee ${toString config.baseFee}"
80+
"--timestamp ${toString config.timestamp}"
81+
"--port ${toString config.port}"
82+
(lib.optionalString (config.blockTime != null) "--block-time ${toString config.blockTime}")
83+
(lib.optionalString (config.state != null) "--state ${config.state}")
84+
(lib.optionalString (config.stateInterval != null) "--state-interval ${toString config.stateInterval}")
85+
(lib.optionalString config.preserveHistoricalStates "--preserve-historical-states")
86+
]);
4887

4988
availability = {
50-
restart = "always";
89+
restart = "on_failure";
90+
};
91+
92+
shutdown = {
93+
command = "kill -TERM $${PROCESS_PID}";
94+
timeout_seconds = 10;
5195
};
5296

5397
readiness_probe = {

0 commit comments

Comments
 (0)