Skip to content

Commit 8ff18c4

Browse files
joanestebanrclaude
andauthored
feat: add L2NetworkConfig with optional InitialLER override (#1558)
## πŸš€ What's New The call to get the initial **Local Exit Root** from the contract requires an archive node. Using the configurable `InitialLER`, we can skip this call. Introduces a new `[L2NetworkConfig]` section in the top-level config to hold L2-specific settings. The first field, `InitialLER`, allows operators to override the initial Local Exit Root without querying the RollupManager contract on L1, and so, let to use an archive-node. - New `L2NetworkConfig` struct in `etherman/config/network.go` - New `[L2NetworkConfig]` section in the main `Config` and `default.go` - `GetInitialLER` in `cmd/run.go` accepts an optional override; if non-nil, the contract call is skipped - Logs the resolved initial LER on startup ## πŸ› Bug Fixes None. ## πŸ“‹ Config Updates New optional field under `[L2NetworkConfig]`: ```toml [L2NetworkConfig] # InitialLER: optional override for the initial Local Exit Root (0x000...000 is a valid value). # If not set, the value is queried from the RollupManager contract on L1. # InitialLER = "0xaabbccdd..." ``` Default: not set (field absent β†’ contract is queried as before). ## ⚠️ Breaking Changes None. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 47b5bde commit 8ff18c4

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

β€Žcmd/run.goβ€Ž

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,12 @@ func start(cliCtx *cli.Context) error {
144144

145145
l1BridgeSync := runBridgeSyncL1IfNeeded(ctx, components, cfg.BridgeL1Sync, reorgDetectorL1,
146146
l1Client, MainnetID, &backfillWg)
147-
initialLER, err := GetInitialLER(cfg.AggSender.RollupCreationBlockL1, rollupDataQuerier)
147+
initialLER, err := GetInitialLER(cfg.L2NetworkConfig.InitialLER,
148+
cfg.AggSender.RollupCreationBlockL1, rollupDataQuerier)
148149
if err != nil {
149150
return fmt.Errorf("failed to get initial local exit root: %w", err)
150151
}
152+
log.Infof("Initial Local Exit Root (LER): %s", initialLER.Hex())
151153

152154
if isNeeded([]string{
153155
aggkitcommon.AGGSENDER, aggkitcommon.AGGSENDERVALIDATOR, aggkitcommon.AGGCHAINPROOFGEN,
@@ -802,8 +804,12 @@ func resolveL1BridgeConfig(cfg *bridgesync.Config, components []string, logprefi
802804
}
803805

804806
func GetInitialLER(
807+
initialLEROverride *common.Hash,
805808
rollupCreationBlockL1 uint64,
806809
rollupDataQuerier *ethermanquierier.RollupDataQuerier) (*common.Hash, error) {
810+
if initialLEROverride != nil {
811+
return initialLEROverride, nil
812+
}
807813
if rollupDataQuerier == nil {
808814
return nil, nil
809815
}

β€Žconfig/config.goβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ type Config struct {
258258
// L1NetworkConfig represents the L1 network config and contains RPC URL alongside L1 contract addresses.
259259
L1NetworkConfig ethermanconfig.L1NetworkConfig
260260

261+
// L2NetworkConfig holds configuration specific to the L2 network.
262+
L2NetworkConfig ethermanconfig.L2NetworkConfig
263+
261264
// REST contains the configuration settings for the REST service in the Aggkit
262265
REST common.RESTConfig
263266

β€Žconfig/config_test.goβ€Ž

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func TestLoadDefaultConfig(t *testing.T) {
8181
cfgL2Multidownloader.BlockFinality = aggkittypes.LatestBlock
8282
cfgL2Multidownloader.Enabled = false
8383
require.Equal(t, cfgL2Multidownloader, cfg.L2Multidownloader)
84+
require.Nil(t, cfg.L2NetworkConfig.InitialLER)
8485
}
8586

8687
func TestLoadConfigWithSaveConfigFile(t *testing.T) {
@@ -125,6 +126,57 @@ func newCliContextConfigFlag(t *testing.T, values ...string) *cli.Context {
125126
return cli.NewContext(nil, flagSet, nil)
126127
}
127128

129+
func TestL2NetworkConfigInitialLER(t *testing.T) {
130+
specificHash := "0xaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccdd"
131+
zeroHash := "0x0000000000000000000000000000000000000000000000000000000000000000"
132+
133+
tests := []struct {
134+
name string
135+
toml string
136+
expectNil bool
137+
expectedValue string
138+
}{
139+
{
140+
name: "InitialLER set to a specific hash",
141+
toml: `
142+
[L2NetworkConfig]
143+
InitialLER = "` + specificHash + `"
144+
`,
145+
expectNil: false,
146+
expectedValue: specificHash,
147+
},
148+
{
149+
name: "InitialLER set to zero hash is valid and not nil",
150+
toml: `
151+
[L2NetworkConfig]
152+
InitialLER = "` + zeroHash + `"
153+
`,
154+
expectNil: false,
155+
expectedValue: zeroHash,
156+
},
157+
{
158+
name: "InitialLER not set returns nil",
159+
toml: ``,
160+
expectNil: true,
161+
},
162+
}
163+
164+
for _, tt := range tests {
165+
t.Run(tt.name, func(t *testing.T) {
166+
cfg, err := LoadFileFromString(tt.toml, ConfigType)
167+
require.NoError(t, err)
168+
require.NotNil(t, cfg)
169+
170+
if tt.expectNil {
171+
require.Nil(t, cfg.L2NetworkConfig.InitialLER)
172+
} else {
173+
require.NotNil(t, cfg.L2NetworkConfig.InitialLER)
174+
require.Equal(t, tt.expectedValue, cfg.L2NetworkConfig.InitialLER.Hex())
175+
}
176+
})
177+
}
178+
}
179+
128180
func TestLoadConfigWithDeprecatedFields(t *testing.T) {
129181
tmpFile, err := os.CreateTemp("", "ut_config")
130182
require.NoError(t, err)

β€Žconfig/default.goβ€Ž

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ BlocksChunkSize = {{L1Config.BlocksChunkSize}}
8484
BackoffMultiplier = 2.0
8585
HashFromJSON = true
8686
87+
[L2NetworkConfig]
88+
# InitialLER: optional override for the initial Local Exit Root (0x000...000 is a valid value).
89+
# If not set, the value is queried from the RollupManager contract on L1.
90+
# InitialLER =
91+
8792
[ReorgDetectorL1]
8893
DBPath = "{{PathRWData}}/reorgdetectorl1.sqlite"
8994
FinalizedBlock = "FinalizedBlock"

β€Žetherman/config/network.goβ€Ž

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ type CommonConfig struct {
2626
L2RPC RPCClientConfig `mapstructure:"L2RPC"`
2727
}
2828

29+
// L2NetworkConfig holds configuration specific to the L2 network
30+
type L2NetworkConfig struct {
31+
// InitialLER is an optional override for the initial Local Exit Root.
32+
// If set, the RollupManager contract is not queried for the initial LER.
33+
// Note: 0x000...000 is a valid value. Omit this field to use the contract.
34+
InitialLER *gethcommon.Hash `mapstructure:"InitialLER"`
35+
}
36+
2937
// L1NetworkConfig represents the configuration of the network used in L1
3038
type L1NetworkConfig struct {
3139
// RPC client configuration for the L1 network

0 commit comments

Comments
Β (0)