Reference
The following tables break down each configuration section and field available for customizing your devnet. Use these references to understand the structure, defaults, and purpose of every option.
For the latest defaults and advanced options, always refer to the source code in src/config/input_parser.star.
Dev Configuration
The dev section controls high-level deployment options for the devnet.
dev:
l1_backend: ethereum-package
should_deploy_l1: true
should_deploy_matic_contracts: true
| Field | Type | Default | Description |
|---|---|---|---|
| l1_backend | string | ethereum-package | L1 backend to use: ethereum-package for full devnet or anvil for lightweight |
| should_deploy_l1 | bool | true | Whether to deploy the L1 chain |
| l1_rpc_url | string | - | RPC URL of an existing L1 to connect to. Required when should_deploy_l1: false. The L1 must run Amsterdam (Glamsterdam), the fork L1 scripts are simulated with |
| should_deploy_matic_contracts | bool | true | Whether to deploy the contract suite (plasma bridge, MATIC→POL migration, pos bridge, fx-portal, sPOL/LST) |
| l2_el_genesis_filepath | string | - | Path to a pre-built L2 EL genesis file. Required when should_deploy_matic_contracts: false |
| l2_cl_genesis_filepath | string | - | Path to a pre-built L2 CL genesis file. Required when should_deploy_matic_contracts: false |
| matic_contract_addresses_filepath | string | - | Path to a JSON of already-deployed MATIC contract addresses. Required when should_deploy_matic_contracts: false |
L1 Configuration
The package supports two L1 backends, configured via the dev.l1_backend parameter:
ethereum-package(default): Full-featured L1 devnet with multi-client supportanvil: Lightweight local Ethereum node for rapid testing
Ethereum Package Backend
When using l1_backend: ethereum-package (default), customize the L1 devnet with an ethereum_package property in your args file. The available options mirror those from the ethereum-package. For the complete YAML schema and default values, refer to the ethereum-package configuration documentation.
dev:
l1_backend: ethereum-package # default
ethereum_package:
participants:
- cl_type: lighthouse
el_type: geth
network_params:
preset: minimal
seconds_per_slot: 1
participants
| Field | Type | Default | Description |
|---|---|---|---|
| cl_type | string | lighthouse | Consensus Layer (CL) client type |
| cl_image | string | sigp/lighthouse:v8.3.2 | Image for the CL client |
| el_type | string | geth | Execution Layer (EL) client type |
| el_image | string | ethereum/client-go:v1.17.10 | Image for the EL client |
| use_separate_vc | bool | true | Run the validator client in its own container |
| vc_type | string | lighthouse | Validator client type |
| vc_image | string | sigp/lighthouse:v8.3.2 | Image for the validator client |
| supernode | bool | true | Custody all PeerDAS data columns, required since Fulu is active |
network_params
| Field | Type | Default | Description |
|---|---|---|---|
| preset | string | minimal | Network preset, useful for rapid testing and development |
| seconds_per_slot | int | 1 | Number of seconds per slot on the Beacon chain |
| altair_fork_epoch … fulu_fork_epoch | int | 0 | Every L1 fork up to Fulu activates at genesis |
| bpo_1_epoch, bpo_2_epoch | int | 0 | Blob parameter only (BPO) forks; BPO 3 to 5 stay disabled |
| gloas_fork_epoch | int | 0 | Glamsterdam (Gloas on the CL, Amsterdam on the EL) at genesis |
Anvil Backend
When using l1_backend: anvil, customize the Anvil L1 with an anvil property in your args file. Anvil is a lightweight local Ethereum node from the Foundry toolkit, ideal for rapid testing scenarios.
dev:
l1_backend: anvil
anvil:
network_id: "3151908"
block_time: 1
slots_in_epoch: 2
| Field | Type | Default | Description |
|---|---|---|---|
| image | string | ghcr.io/foundry-rs/foundry:v1.9.0 | Anvil container image |
| network_id | string | 3151908 | L1 network/chain ID |
| block_time | int | 1 | Block time in seconds |
| slots_in_epoch | int | 2 | Number of slots per epoch (block_time × slots_in_epoch = seconds to transition from latest to safest) |
L2 Configuration
To customize the L2 devnet, include a polygon_pos_package property in your args file.
polygon_pos_package:
log_level: info
log_format: text
participants:
- kind: validator
cl_type: heimdall-v2
el_type: bor
count: 2
network_params:
el_block_interval_seconds: 2
el_gas_limit: 60_000_000
additional_services:
- observability
Top-Level Parameters
| Field | Type | Default | Description |
|---|---|---|---|
| log_level | string | info | Global log level for all participants: error, warn, info, debug, or trace |
| log_format | string | text | Global log format for all participants: text or json |
These global settings apply to all participants unless overridden at the participant level with cl_log_level, cl_log_format, el_log_level, or el_log_format.
participants
Default: a single validator.
| Field | Type | Default | Description |
|---|---|---|---|
| kind | string | validator | Role of the node in the network: validator or rpc. Use el_bor_archive_mode for archive retention. |
| cl_type | string | heimdall-v2 | Consensus Layer (CL) client type |
| cl_image | string | ghcr.io/0xpolygon/heimdall-v2:v0.13.2 | Image for the CL client |
| cl_queue_image | string | rabbitmq:4.4.0 | Image for the CL queue |
| cl_log_level | string | info | Log level for the CL client |
| cl_log_format | string | text | Log format for the CL client |
| cl_min_retain_blocks | int | 0 | Minimal distance from current height to retain height |
| cl_compact_enabled | bool | false | Compaction enabling. |
| cl_compaction_interval | int | 1000 | Minimal blocks necessary to run a new compaction routine |
| cl_storage_pruning_interval | string | 10m0s | Interval between prune routines. |
| cl_indexer_pruning_enabled | bool | false | Pruning enabling. |
| el_type | string | bor | Execution Layer (EL) client type: bor |
| el_image | string | ghcr.io/0xpolygon/bor:v2.11.0 | Image for the EL client (bor: ghcr.io/0xpolygon/bor:v2.11.0) |
| el_log_level | string | info | Log level for the EL client |
| el_log_format | string | text | Log format for the EL client |
| el_bor_produce_witness | bool | false | Allow bor to start producing witnesses |
| el_bor_sync_with_witness | bool | false | Enable bor to sync new blocks using witnesses |
| el_bor_stateless_parallel_import | bool | false | Enable bor to use parallel import in stateless mode (requires el_bor_sync_with_witness) |
| el_bor_archive_mode | bool | false | Run bor with gcmode=archive and full history retention. Orthogonal to kind — set on a validator or rpc node. Required for debug_traceTransaction on past blocks. The default single-node config sets this to true on the validator. |
| el_bor_use_sequence_store | bool | false | Render bor's [sequencer] config section against the enclave sequence store (preconfirmation experiment). Requires an el_image built from the bor sequencer branch; setting it on any participant deploys the store (see sequence_store_params). |
| count | int | 1 | Number of nodes to spin up for this participant |
setup_images
| Field | Type | Default | Description |
|---|---|---|---|
| contract_deployer | string | ghcr.io/0xpolygon/pos-contract-deployer:0.0.7 | Image used to deploy MATIC contracts to L1 |
| el_genesis_builder | string | ghcr.io/0xpolygon/pos-el-genesis-builder:96a19dd-r1 | Image used to create the L2 EL genesis file |
| validator_config_generator | string | ghcr.io/0xpolygon/pos-validator-config-generator:0.13.2 | Image used to generate validator configs |
network_params
You can check the admin private key and mnemonic default values at src/config/input_parser.star.
| Field | Type | Default | Description |
|---|---|---|---|
| admin_private_key | string | 0xd403...60ea | Private key used to deploy Polygon PoS contracts on both L1 and L2 |
| preregistered_validator_keys_mnemonic | string | sibling lend brave | Mnemonic for validator keystores |
| validator_stake_amount_eth | int | 10000 | Amount of ether to stake for each validator |
| validator_top_up_fee_amount_eth | int | 2000 | Top up fee amount in ether for each validator |
| cl_environment | string | - | CL environment: mainnet, mumbai, or local (optional) |
| cl_span_poll_interval | string | 5s | Span poll interval on the CL chain |
| cl_checkpoint_poll_interval | string | 5s | Checkpoint poll interval on the CL chain |
| cl_max_age_num_blocks | int | 100000 | Genesis evidence setting, useful to set smaller pruning intervals |
| cl_avg_checkpoint_length | string | 8 | Average number of blocks per checkpoint (heimdall chain_manager.params.chain_params.avg_checkpoint_length) |
| cl_checkpoint_buffer_time | string | 10s | Checkpoint buffer time (heimdall chain_manager.params.chain_params.checkpoint_buffer_time) |
| el_block_interval_seconds | int | 1 | Seconds per block on the EL chain |
| el_sprint_duration | int | 16 | Duration of an EL sprint (blocks) |
| el_span_duration | int | 128 | Duration of an EL span (blocks). |
| el_gas_limit | int | 200_000_000 | EL gas limit. Mirrors amoy BP (mainnet BP: 120M) |
| jaipur_fork_block | int | 0 | Block number for Jaipur hard fork activation |
| delhi_fork_block | int | 0 | Block number for Delhi hard fork activation |
| indore_fork_block | int | 0 | Block number for Indore hard fork activation |
| agra_fork_block | int | 0 | Block number for Agra hard fork activation |
| napoli_fork_block | int | 0 | Block number for Napoli hard fork activation |
| ahmedabad_fork_block | int | 0 | Block number for Ahmedabad hard fork activation |
| bhilai_fork_block | int | 0 | Block number for Bhilai hard fork activation |
| rio_fork_block | int | 128 | Block number for Rio hard fork activation |
| madhugiri_fork_block | int | 128 | Block number for Madhugiri hard fork activation |
| madhugiri_pro_fork_block | int | 128 | Block number for Madhugiri Pro hard fork activation |
| dandeli_fork_block | int | 128 | Block number for Dandeli hard fork activation |
| lisovo_fork_block | int | 128 | Block number for Lisovo hard fork activation |
| lisovo_pro_fork_block | int | 128 | Block number for Lisovo Pro hard fork activation |
| giugliano_fork_block | int | 128 | Block number for Giugliano hard fork activation |
| chicago_fork_block | int | 128 | Block number for Chicago hard fork activation |
| valencia_fork_block | int | 128 | Block number for Valencia hard fork activation (bor >= 2.10.0) |
| austin_fork_block | int | 128 | Block number for Austin hard fork activation (bor >= 2.10.0) |
| hampi_fork_block | int | 128 | Block number for Hampi hard fork activation (bor >= 2.10.1) |
| uburu_fork_block | int | 128 | Block number for Uburu hard fork activation (bor >= 2.11.0) |
additional_services
The additional_services array lets you enable optional tools and utilities alongside your devnet. These are not configuration options themselves, but rather extra services you can include by listing their names in the array.
| Service | Description |
|---|---|
blockscout | Blockchain explorer for viewing blocks, transactions, and accounts - Coming soon |
bridge_spammer | Bridge funds from L1 to L2 to simulate network load |
ethstats_server | Visual interface for tracking network status |
nginx | nginx least-connections RPC load balancer in front of all non-stateless bor nodes (see nginx_params) |
observability | Monitoring stack: deploys Prometheus, Grafana, and Panoptichain (see observability_params) |
status_checker | Perform regular status checks to track and monitor the health of the network |
tx_spammer | Send transactions to the network to simulate load |
nginx_params
Only allowed when nginx is listed in additional_services.
The nginx service deploys nginx with every bor node (validators, rpc, and archive alike) as an upstream — except stateless-sync nodes (el_bor_sync_with_witness: true), whose disabled txpool means they cannot accept transactions — balanced with least_conn (each request goes to the upstream with the fewest active connections), which spreads concurrent requests across all nodes — a good fit for load tests, particularly with long-held calls like eth_sendRawTransactionSync that occupy a bor RPC execution-pool slot until the receipt lands. There is no caching, retry logic (beyond connection-error failover), or method awareness.
# The JSON-RPC endpoint is served at the root path.
cast block-number --rpc-url "$(kurtosis port print pos nginx rpc)"
| Field | Type | Default | Description |
|---|---|---|---|
| image | string | nginx:1.31.8-alpine | Image used to deploy nginx |
ethstats_server_params
| Field | Type | Default | Description |
|---|---|---|---|
| image | string | europe-west2-docker.pkg.dev/prj-polygonlabs-devtools-dev/public/ethstats-server:9da2124 | Image used to deploy the ethstats server |
| ws_secret | string | sharedsecret | Shared secret used to authenticate nodes reporting to the ethstats server |
observability_params
Only allowed when observability is listed in additional_services.
| Field | Type | Default | Description |
|---|---|---|---|
| deploy_panoptichain | bool | true | Deploy Panoptichain alongside Prometheus and Grafana. Set to false to skip it |
sequence_store_params
Deployed if and only if at least one participant sets el_bor_use_sequence_store: true. One store is shared by the whole devnet: validators publish to the ingress, RPC nodes consume the gateway stream.
| Field | Type | Default | Description |
|---|---|---|---|
| image | string | seqstore:local | Sequence-store image (ingress/gateway/auditor), built locally from the sequence-store repo |
| redpanda_image | string | redpandadata/redpanda:v26.2.2 | Redpanda broker image |
| redpanda_count | int | 1 | Broker count. With more than one, the topic is created at RF=count with majority min.insync.replicas |
| gateway_count | int | 1 | Gateway count. With more than one, an envoy load balancer takes the canonical seqstore-gateway name |
| envoy_image | string | envoyproxy/envoy:v1.40.2 | Envoy image for the gateway load balancer (only used when gateway_count > 1) |
status_checker_params
| Field | Type | Default | Description |
|---|---|---|---|
| image | string | ghcr.io/0xpolygon/status-checker:v0.2.10 | Image used to deploy the status checker |