Commit f15108c
feat(anvil): support multiple fork URLs with round-robin load balancing (foundry-rs#14280)
* feat(anvil): support multiple fork URLs with fallback
Allow `--fork-url` to be specified multiple times to distribute RPC
requests across endpoints using Alloy's FallbackService. Endpoints are
scored by latency and success rate; unhealthy endpoints (429s, timeouts)
are automatically deprioritized.
Uses active_transport_count=1 for sequential best-endpoint routing.
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d85e6-b08f-748c-8f05-17ebee8e17f8
* fix: fmt
* feat(config): support multi-endpoint `endpoints` array in foundry.toml
Add `endpoints` key to `[rpc_endpoints]` config as a backwards-compatible
alternative to `endpoint`. When an alias with multiple endpoints is used
as `--fork-url`, all URLs are expanded for multi-endpoint forking.
Example:
[rpc_endpoints]
mainnet = { endpoints = ["https://rpc1.example.com", "https://rpc2.example.com"], retries = 5 }
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d85e6-b08f-748c-8f05-17ebee8e17f8
* test: add guardrail tests and handle curl_mode in build_fallback
- Add test confirming `requires = "fork_url"` guards still fire with Vec
- Bail on curl_mode in build_fallback (incompatible with multi-endpoint)
- Clean up redundant extra_endpoints default in From impl
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d85e6-b08f-748c-8f05-17ebee8e17f8
* refactor(anvil): consolidate eth_rpc_url into fork_urls
Remove duplicate `eth_rpc_url` field from `NodeConfig` and
`ClientForkConfig`. The primary URL is now always `fork_urls[0]`,
eliminating the invariant that `eth_rpc_url == fork_urls[0]`.
- `ClientForkConfig::eth_rpc_url()` is now an accessor returning `&str`
- `NodeConfig::with_eth_rpc_url()` kept as convenience, wraps into `fork_urls`
- Checks for forking enabled use `fork_urls.is_empty()` instead of `eth_rpc_url.is_none()`
Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8b67-c7cc-764f-bb5e-74b6e8fa6858
* refactor(anvil): simplify update_url to replace all fork_urls
When resetting the fork via anvil_reset or anvil_setRpcUrl, the intent
is to switch the fork target entirely — not swap one endpoint in a
load-balanced pool. Replace the whole fork_urls vec with the single
new URL instead of mutating fork_urls[0] in-place.
Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8b67-c7cc-764f-bb5e-74b6e8fa6858
* refactor(anvil): rename update_url to update_urls taking Vec<String>
Accepts a Vec so the reset/update path can reconstruct a fallback
provider when given multiple URLs, instead of always collapsing to
a single endpoint.
Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8b67-c7cc-764f-bb5e-74b6e8fa6858
* refactor(anvil): update ClientFork::reset to accept Vec<String>
Change reset(url: Option<String>) to reset(urls: Vec<String>) so the
reset path can preserve multi-endpoint fallback. The underlying
MaybeForkedDatabase::maybe_reset still takes Option<String> since
it ignores the url anyway (marked TODO upstream).
Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8b67-c7cc-764f-bb5e-74b6e8fa6858
* refactor: use Vec<String> throughout reset path
Commit to Vec<String> in MaybeForkedDatabase::maybe_reset,
ForkedDatabase::reset, and ClientFork::reset. The Option<String> →
Vec<String> conversion now happens only at the RPC boundary
(Forking.json_rpc_url in reset_fork).
Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8b67-c7cc-764f-bb5e-74b6e8fa6858
* fix: fmt
Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019d8b67-c7cc-764f-bb5e-74b6e8fa6858
* round-robin for load-balance
* comments
* fix(anvil): sync fork_urls after anvil_setRpcUrl and anvil_reset
Fix two bugs where node_config.fork_urls could get out of sync:
1. reset_block_number() now updates node_config.fork_urls before calling
setup_fork_db_config(), preventing stale multi-URL lists from persisting
after anvil_reset with a new URL.
2. anvil_setRpcUrl now also updates node_config.fork_urls, so subsequent
anvil_reset(None) uses the correct URL instead of reverting to the
original startup URL.
Added regression tests for both scenarios.
Amp-Thread-ID: https://ampcode.com/threads/T-019db0c0-6038-7428-8483-365402ff31a3
Co-authored-by: Amp <amp@ampcode.com>
* chore: fmt
Amp-Thread-ID: https://ampcode.com/threads/T-019db0c0-6038-7428-8483-365402ff31a3
Co-authored-by: Amp <amp@ampcode.com>
---------
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com>
Co-authored-by: steven <corderosteven6@gmail.com>
Co-authored-by: stevencartavia <112043913+stevencartavia@users.noreply.github.com>
Co-authored-by: zerosnacks <zerosnacks@protonmail.com>
Co-authored-by: Amp <amp@ampcode.com>1 parent f609179 commit f15108c
13 files changed
Lines changed: 565 additions & 71 deletions
File tree
- crates
- anvil
- src
- eth
- backend
- mem
- tests/it
- common/src/provider
- config/src
- evm/core/src/fork
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
227 | 227 | | |
228 | 228 | | |
229 | 229 | | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
230 | 242 | | |
231 | 243 | | |
232 | 244 | | |
| |||
260 | 272 | | |
261 | 273 | | |
262 | 274 | | |
263 | | - | |
| 275 | + | |
264 | 276 | | |
265 | 277 | | |
266 | 278 | | |
| |||
270 | 282 | | |
271 | 283 | | |
272 | 284 | | |
273 | | - | |
| 285 | + | |
274 | 286 | | |
275 | 287 | | |
276 | 288 | | |
| |||
426 | 438 | | |
427 | 439 | | |
428 | 440 | | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
429 | 445 | | |
430 | 446 | | |
431 | 447 | | |
432 | 448 | | |
433 | 449 | | |
434 | 450 | | |
435 | 451 | | |
436 | | - | |
| 452 | + | |
437 | 453 | | |
438 | 454 | | |
439 | 455 | | |
| |||
630 | 646 | | |
631 | 647 | | |
632 | 648 | | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
633 | 652 | | |
634 | 653 | | |
635 | | - | |
636 | | - | |
637 | | - | |
638 | | - | |
639 | | - | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
640 | 688 | | |
641 | 689 | | |
642 | 690 | | |
| |||
965 | 1013 | | |
966 | 1014 | | |
967 | 1015 | | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
968 | 1077 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
134 | 134 | | |
135 | 135 | | |
136 | 136 | | |
137 | | - | |
138 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
139 | 141 | | |
140 | 142 | | |
141 | | - | |
| 143 | + | |
142 | 144 | | |
143 | 145 | | |
144 | 146 | | |
| |||
268 | 270 | | |
269 | 271 | | |
270 | 272 | | |
271 | | - | |
| 273 | + | |
272 | 274 | | |
273 | 275 | | |
274 | 276 | | |
275 | 277 | | |
276 | 278 | | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
277 | 286 | | |
278 | 287 | | |
279 | 288 | | |
| |||
393 | 402 | | |
394 | 403 | | |
395 | 404 | | |
396 | | - | |
| 405 | + | |
397 | 406 | | |
398 | 407 | | |
399 | 408 | | |
| |||
466 | 475 | | |
467 | 476 | | |
468 | 477 | | |
469 | | - | |
| 478 | + | |
470 | 479 | | |
471 | 480 | | |
472 | 481 | | |
| |||
855 | 864 | | |
856 | 865 | | |
857 | 866 | | |
858 | | - | |
| 867 | + | |
859 | 868 | | |
860 | 869 | | |
861 | | - | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
862 | 880 | | |
863 | 881 | | |
864 | 882 | | |
| |||
891 | 909 | | |
892 | 910 | | |
893 | 911 | | |
894 | | - | |
| 912 | + | |
895 | 913 | | |
896 | 914 | | |
897 | 915 | | |
| |||
1017 | 1035 | | |
1018 | 1036 | | |
1019 | 1037 | | |
1020 | | - | |
| 1038 | + | |
1021 | 1039 | | |
1022 | 1040 | | |
1023 | 1041 | | |
| |||
1145 | 1163 | | |
1146 | 1164 | | |
1147 | 1165 | | |
1148 | | - | |
| 1166 | + | |
1149 | 1167 | | |
1150 | 1168 | | |
1151 | 1169 | | |
| |||
1208 | 1226 | | |
1209 | 1227 | | |
1210 | 1228 | | |
1211 | | - | |
| 1229 | + | |
1212 | 1230 | | |
1213 | 1231 | | |
1214 | 1232 | | |
| |||
1248 | 1266 | | |
1249 | 1267 | | |
1250 | 1268 | | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
1251 | 1273 | | |
1252 | 1274 | | |
1253 | 1275 | | |
| |||
1409 | 1431 | | |
1410 | 1432 | | |
1411 | 1433 | | |
| 1434 | + | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
| 1452 | + | |
1412 | 1453 | | |
1413 | 1454 | | |
1414 | 1455 | | |
| |||
1419 | 1460 | | |
1420 | 1461 | | |
1421 | 1462 | | |
1422 | | - | |
| 1463 | + | |
1423 | 1464 | | |
1424 | 1465 | | |
1425 | 1466 | | |
| |||
1432 | 1473 | | |
1433 | 1474 | | |
1434 | 1475 | | |
| 1476 | + | |
1435 | 1477 | | |
1436 | 1478 | | |
1437 | 1479 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
416 | 416 | | |
417 | 417 | | |
418 | 418 | | |
419 | | - | |
| 419 | + | |
420 | 420 | | |
421 | 421 | | |
422 | 422 | | |
| |||
527 | 527 | | |
528 | 528 | | |
529 | 529 | | |
530 | | - | |
| 530 | + | |
531 | 531 | | |
532 | 532 | | |
533 | 533 | | |
| |||
543 | 543 | | |
544 | 544 | | |
545 | 545 | | |
546 | | - | |
547 | | - | |
| 546 | + | |
| 547 | + | |
548 | 548 | | |
| 549 | + | |
| 550 | + | |
549 | 551 | | |
550 | 552 | | |
551 | 553 | | |
| |||
1791 | 1793 | | |
1792 | 1794 | | |
1793 | 1795 | | |
1794 | | - | |
| 1796 | + | |
1795 | 1797 | | |
1796 | 1798 | | |
1797 | 1799 | | |
| |||
0 commit comments