@@ -162,9 +162,14 @@ function getAnvilOptions(
162162 forkUrl,
163163 port,
164164 forkBlockNumber,
165+ mnemonic :
166+ 'you twelve word test phrase boat cat like this example dog car' , // mnemonic for deterministic accounts - should not have delegated accounts
165167 } ;
166168}
167169
170+ // Counter to ensure unique ports for each fork instance
171+ let forkCounter = 0 ;
172+
168173// Controls the current running forks to avoid starting the same fork twice
169174let runningForks : Record < number , Anvil > = { } ;
170175
@@ -177,9 +182,14 @@ export async function stopAnvilForks() {
177182 } ) ,
178183 ) ;
179184 runningForks = { } ;
185+ // Reset fork counter after stopping all forks to prevent unbounded growth
186+ forkCounter = 0 ;
180187}
181188
182189// Stop a specific anvil fork
190+ // Note: Since forks are no longer reused (each startFork() creates a new instance),
191+ // this function may not reliably find forks without tracking the exact port.
192+ // For cleanup, prefer using stopAnvilForks() which stops all forks.
183193export async function stopAnvilFork (
184194 network : NetworkSetup ,
185195 jobId = Number ( process . env . VITEST_WORKER_ID ) || 0 ,
@@ -188,8 +198,10 @@ export async function stopAnvilFork(
188198 const anvilOptions = getAnvilOptions ( network , blockNumber ) ;
189199
190200 const defaultAnvilPort = 8545 ;
201+ // Note: This port calculation doesn't account for forkCounter, so it may not find the fork
202+ // if it was created with a counter offset. This function is kept for compatibility but
203+ // stopAnvilForks() is recommended for cleanup.
191204 const port = ( anvilOptions . port || defaultAnvilPort ) + jobId ;
192- // Avoid starting fork if it was running already
193205 if ( ! runningForks [ port ] ) return ;
194206
195207 await runningForks [ port ] . stop ( ) ;
@@ -201,6 +213,9 @@ export async function stopAnvilFork(
201213 In vitest, each thread is assigned a unique, numerical id (`process.env.VITEST_POOL_ID`).
202214 When jobId is provided, the fork uses this id to create a different local rpc url (e.g. `http://127.0.0.1:<8545+jobId>/`
203215 so that tests can be run in parallel (depending on the number of threads of the host machine)
216+
217+ IMPORTANT: Each call to startFork() creates a new fork instance with a unique port.
218+ This ensures complete isolation between test suites, preventing state interference and snapshot collisions.
204219*/
205220export async function startFork (
206221 network : NetworkSetup ,
@@ -212,7 +227,11 @@ export async function startFork(
212227 const anvilOptions = getAnvilOptions ( network , blockNumber ) ;
213228
214229 const defaultAnvilPort = 8545 ;
215- const port = ( anvilOptions . port || defaultAnvilPort ) + jobId ;
230+ const basePort = anvilOptions . port || defaultAnvilPort ;
231+ // Calculate unique port: basePort + jobId + (forkCounter * 100)
232+ // This ensures each fork gets a unique port while maintaining network separation
233+ const port = basePort + jobId + forkCounter * 100 ;
234+ forkCounter ++ ;
216235
217236 if ( ! anvilOptions . forkUrl ) {
218237 throw Error (
@@ -221,10 +240,11 @@ export async function startFork(
221240 }
222241 const rpcUrl = `http://127.0.0.1:${ port } ` ;
223242
224- console . log ( 'checking rpcUrl' , port , runningForks ) ;
225-
226- // Avoid starting fork if it was running already
227- if ( runningForks [ port ] ) return { rpcUrl } ;
243+ console . log ( 'Starting new fork' , {
244+ port,
245+ forkBlockNumber : blockNumber ?? anvilOptions . forkBlockNumber ,
246+ runningForks : Object . keys ( runningForks ) . length ,
247+ } ) ;
228248
229249 // https://www.npmjs.com/package/@viem /anvil
230250 // Pass startTimeout directly to createAnvil - it defaults to 10_000ms
0 commit comments