@@ -3,11 +3,14 @@ package main
33import (
44 "encoding/json"
55 "fmt"
6+ "math/big"
67 "os"
78 "strconv"
9+ "strings"
810 "testing"
911
1012 "github.com/ethereum-optimism/optimism/op-node/chaincfg"
13+ "github.com/ethereum-optimism/optimism/op-node/rollup"
1114 "github.com/ethereum-optimism/optimism/op-program/chainconfig"
1215 "github.com/ethereum-optimism/optimism/op-program/client/boot"
1316 "github.com/ethereum-optimism/optimism/op-program/host/config"
@@ -90,12 +93,10 @@ func TestNetwork(t *testing.T) {
9093 verifyArgsInvalid (t , "invalid network: \" bar\" " , replaceRequiredArg ("--network" , "bar" ))
9194 })
9295
93- t .Run ("Required" , func (t * testing.T ) {
94- verifyArgsInvalid (t , "flag rollup.config or network is required" , addRequiredArgsExcept ("--network" ))
95- })
96-
97- t .Run ("DisallowNetworkAndRollupConfig" , func (t * testing.T ) {
98- verifyArgsInvalid (t , "cannot specify both rollup.config and network" , addRequiredArgs ("--rollup.config=foo" ))
96+ t .Run ("AllowNetworkAndRollupConfig" , func (t * testing.T ) {
97+ configFile , rollupCfg := writeRollupConfigWithChainID (t , 4297842 )
98+ cfg := configForArgs (t , addRequiredArgs ("--rollup.config" , configFile ))
99+ require .Equal (t , []* rollup.Config {chaincfg .OPSepolia (), rollupCfg }, cfg .Rollups )
99100 })
100101
101102 t .Run ("RollupConfig" , func (t * testing.T ) {
@@ -107,6 +108,15 @@ func TestNetwork(t *testing.T) {
107108 require .Equal (t , * chaincfg .OPSepolia (), * cfg .Rollups [0 ])
108109 })
109110
111+ t .Run ("Multiple" , func (t * testing.T ) {
112+ cfg := configForArgs (t , addRequiredArgsExcept ("--network" , "--network=op-mainnet,op-sepolia" ))
113+ require .Len (t , cfg .Rollups , 2 )
114+ opMainnetCfg , err := chaincfg .GetRollupConfig ("op-mainnet" )
115+ require .NoError (t , err )
116+ require .Equal (t , * opMainnetCfg , * cfg .Rollups [0 ])
117+ require .Equal (t , * chaincfg .OPSepolia (), * cfg .Rollups [1 ])
118+ })
119+
110120 for _ , name := range chaincfg .AvailableNetworks () {
111121 name := name
112122 expected , err := chaincfg .GetRollupConfig (name )
@@ -141,17 +151,20 @@ func TestDataFormat(t *testing.T) {
141151}
142152
143153func TestL2 (t * testing.T ) {
144- expected := "https://example.com:8545"
145- cfg := configForArgs (t , addRequiredArgs ("--l2" , expected ))
146- require .Equal (t , []string {expected }, cfg .L2URLs )
147- }
154+ t .Run ("Single" , func (t * testing.T ) {
155+ expected := "https://example.com:8545"
156+ cfg := configForArgs (t , addRequiredArgs ("--l2" , expected ))
157+ require .Equal (t , []string {expected }, cfg .L2URLs )
158+ })
148159
149- func TestL2Genesis (t * testing.T ) {
150- t . Run ( "RequiredWithCustomNetwork" , func ( t * testing. T ) {
151- rollupCfgFile := writeValidRollupConfig ( t )
152- verifyArgsInvalid (t , "flag l2.genesis is required" , addRequiredArgsExcept ( "--network" , "--rollup.config" , rollupCfgFile ) )
160+ t . Run ( "Multiple" , func (t * testing.T ) {
161+ expected := [] string { "https://example.com:8545" , "https://example.com:9000" }
162+ cfg := configForArgs ( t , addRequiredArgs ( "--l2" , strings . Join ( expected , "," )) )
163+ require . Equal (t , expected , cfg . L2URLs )
153164 })
165+ }
154166
167+ func TestL2Genesis (t * testing.T ) {
155168 t .Run ("Valid" , func (t * testing.T ) {
156169 rollupCfgFile := writeValidRollupConfig (t )
157170 genesisFile := writeValidGenesis (t )
@@ -165,6 +178,31 @@ func TestL2Genesis(t *testing.T) {
165178 })
166179}
167180
181+ func TestMultipleNetworkConfigs (t * testing.T ) {
182+ t .Run ("MultipleCustomChains" , func (t * testing.T ) {
183+ rollupFile1 , rollupCfg1 := writeRollupConfigWithChainID (t , 1 )
184+ rollupFile2 , rollupCfg2 := writeRollupConfigWithChainID (t , 2 )
185+ genesisFile1 , chainCfg1 := writeGenesisFileWithChainID (t , 1 )
186+ genesisFile2 , chainCfg2 := writeGenesisFileWithChainID (t , 2 )
187+ cfg := configForArgs (t , addRequiredArgsExcept ("--network" ,
188+ "--rollup.config" , rollupFile1 + "," + rollupFile2 ,
189+ "--l2.genesis" , genesisFile1 + "," + genesisFile2 ))
190+ require .Equal (t , []* rollup.Config {rollupCfg1 , rollupCfg2 }, cfg .Rollups )
191+ require .Equal (t , []* params.ChainConfig {chainCfg1 , chainCfg2 }, cfg .L2ChainConfigs )
192+ })
193+
194+ t .Run ("MixNetworkAndCustomChains" , func (t * testing.T ) {
195+ rollupFile , rollupCfg := writeRollupConfigWithChainID (t , 1 )
196+ genesisFile , chainCfg := writeGenesisFileWithChainID (t , 1 )
197+ cfg := configForArgs (t , addRequiredArgsExcept ("--network" ,
198+ "--network" , "op-sepolia" ,
199+ "--rollup.config" , rollupFile ,
200+ "--l2.genesis" , genesisFile ))
201+ require .Equal (t , []* rollup.Config {chaincfg .OPSepolia (), rollupCfg }, cfg .Rollups )
202+ require .Equal (t , []* params.ChainConfig {chainconfig .OPSepoliaChainConfig (), chainCfg }, cfg .L2ChainConfigs )
203+ })
204+ }
205+
168206func TestL2ChainID (t * testing.T ) {
169207 t .Run ("DefaultToNetworkChainID" , func (t * testing.T ) {
170208 cfg := configForArgs (t , replaceRequiredArg ("--network" , "op-mainnet" ))
@@ -187,11 +225,24 @@ func TestL2ChainID(t *testing.T) {
187225 "--l2.custom" ))
188226 require .Equal (t , boot .CustomChainIDIndicator , cfg .L2ChainID )
189227 })
228+
229+ t .Run ("ZeroWhenMultipleL2ChainsSpecified" , func (t * testing.T ) {
230+ cfg := configForArgs (t , addRequiredArgsExcept ("--network" , "--network" , "op-sepolia,op-mainnet" ))
231+ require .Zero (t , cfg .L2ChainID )
232+ })
190233}
191234
192235func TestL2Head (t * testing.T ) {
193- t .Run ("Required" , func (t * testing.T ) {
194- verifyArgsInvalid (t , "flag l2.head is required" , addRequiredArgsExcept ("--l2.head" ))
236+ t .Run ("RequiredWithOutputRoot" , func (t * testing.T ) {
237+ verifyArgsInvalid (t , "flag l2.head is required when l2.outputroot is specified" , addRequiredArgsExcept ("--l2.head" ))
238+ })
239+
240+ t .Run ("NotAllowedWithAgreedPrestate" , func (t * testing.T ) {
241+ req := requiredArgs ()
242+ delete (req , "--l2.head" )
243+ delete (req , "--l2.outputroot" )
244+ args := append (toArgList (req ), "--l2.head" , l2HeadValue , "--l2.agreed-prestate" , "0x1234" )
245+ verifyArgsInvalid (t , "flag l2.head and l2.agreed-prestate must not be specified together" , args )
195246 })
196247
197248 t .Run ("Valid" , func (t * testing.T ) {
@@ -210,7 +261,7 @@ func TestL2OutputRoot(t *testing.T) {
210261 })
211262
212263 t .Run ("NotRequiredWhenAgreedPrestateProvided" , func (t * testing.T ) {
213- configForArgs (t , addRequiredArgsExcept ( "--l2.outputroot" , "--l2.agreed-prestate" , "0x1234" ))
264+ configForArgs (t , addRequiredArgsExceptMultiple ([] string { "--l2.outputroot" , "--l2.head" } , "--l2.agreed-prestate" , "0x1234" ))
214265 })
215266
216267 t .Run ("Valid" , func (t * testing.T ) {
@@ -225,14 +276,14 @@ func TestL2OutputRoot(t *testing.T) {
225276
226277func TestL2AgreedPrestate (t * testing.T ) {
227278 t .Run ("NotRequiredWhenL2OutputRootProvided" , func (t * testing.T ) {
228- configForArgs (t , addRequiredArgsExcept ( "--l2.outputroot" , "--l2.outputroot " , "0x1234" ))
279+ configForArgs (t , addRequiredArgsExceptMultiple ([] string { "--l2.outputroot" , "--l2.head" }, "--l2.agreed-prestate " , "0x1234" ))
229280 })
230281
231282 t .Run ("Valid" , func (t * testing.T ) {
232283 prestate := "0x1234"
233284 prestateBytes := common .FromHex (prestate )
234285 expectedOutputRoot := crypto .Keccak256Hash (prestateBytes )
235- cfg := configForArgs (t , addRequiredArgsExcept ( "--l2.outputroot" , "--l2.agreed-prestate" , prestate ))
286+ cfg := configForArgs (t , addRequiredArgsExceptMultiple ([] string { "--l2.outputroot" , "--l2.head" } , "--l2.agreed-prestate" , prestate ))
236287 require .Equal (t , expectedOutputRoot , cfg .L2OutputRoot )
237288 require .Equal (t , prestateBytes , cfg .AgreedPrestate )
238289 })
@@ -242,11 +293,11 @@ func TestL2AgreedPrestate(t *testing.T) {
242293 })
243294
244295 t .Run ("Invalid" , func (t * testing.T ) {
245- verifyArgsInvalid (t , config .ErrInvalidAgreedPrestate .Error (), addRequiredArgsExcept ( "--l2.outputroot" , "--l2.agreed-prestate" , "something" ))
296+ verifyArgsInvalid (t , config .ErrInvalidAgreedPrestate .Error (), addRequiredArgsExceptMultiple ([] string { "--l2.outputroot" , "--l2.head" } , "--l2.agreed-prestate" , "something" ))
246297 })
247298
248299 t .Run ("ZeroLength" , func (t * testing.T ) {
249- verifyArgsInvalid (t , config .ErrInvalidAgreedPrestate .Error (), addRequiredArgsExcept ( "--l2.outputroot" , "--l2.agreed-prestate" , "0x" ))
300+ verifyArgsInvalid (t , config .ErrInvalidAgreedPrestate .Error (), addRequiredArgsExceptMultiple ([] string { "--l2.outputroot" , "--l2.head" } , "--l2.agreed-prestate" , "0x" ))
250301 })
251302}
252303
@@ -345,6 +396,12 @@ func TestL2Experimental(t *testing.T) {
345396 cfg := configForArgs (t , addRequiredArgs ("--l2.experimental" , expected ))
346397 require .EqualValues (t , []string {expected }, cfg .L2ExperimentalURLs )
347398 })
399+
400+ t .Run ("Multiple" , func (t * testing.T ) {
401+ expected := []string {"https://example.com:8545" , "https://example.com:9000" }
402+ cfg := configForArgs (t , addRequiredArgs ("--l2.experimental" , strings .Join (expected , "," )))
403+ require .EqualValues (t , expected , cfg .L2ExperimentalURLs )
404+ })
348405}
349406
350407func TestL2BlockNumber (t * testing.T ) {
@@ -431,6 +488,14 @@ func addRequiredArgsExcept(name string, optionalArgs ...string) []string {
431488 return append (toArgList (req ), optionalArgs ... )
432489}
433490
491+ func addRequiredArgsExceptMultiple (remove []string , optionalArgs ... string ) []string {
492+ req := requiredArgs ()
493+ for _ , name := range remove {
494+ delete (req , name )
495+ }
496+ return append (toArgList (req ), optionalArgs ... )
497+ }
498+
434499func replaceRequiredArg (name string , value string ) []string {
435500 req := requiredArgs ()
436501 req [name ] = value
@@ -451,17 +516,40 @@ func requiredArgs() map[string]string {
451516}
452517
453518func writeValidGenesis (t * testing.T ) string {
519+ genesis := l2Genesis
520+ return writeGenesis (t , genesis )
521+ }
522+
523+ func writeGenesisFileWithChainID (t * testing.T , chainID uint64 ) (string , * params.ChainConfig ) {
524+ genesis := * l2Genesis
525+ chainCfg := * genesis .Config
526+ chainCfg .ChainID = new (big.Int ).SetUint64 (chainID )
527+ genesis .Config = & chainCfg
528+ return writeGenesis (t , & genesis ), & chainCfg
529+ }
530+
531+ func writeGenesis (t * testing.T , genesis * core.Genesis ) string {
454532 dir := t .TempDir ()
455- j , err := json .Marshal (l2Genesis )
533+ j , err := json .Marshal (genesis )
456534 require .NoError (t , err )
457535 genesisFile := dir + "/genesis.json"
458536 require .NoError (t , os .WriteFile (genesisFile , j , 0666 ))
459537 return genesisFile
460538}
461539
462540func writeValidRollupConfig (t * testing.T ) string {
541+ return writeRollupConfig (t , chaincfg .OPSepolia ())
542+ }
543+
544+ func writeRollupConfigWithChainID (t * testing.T , chainID uint64 ) (string , * rollup.Config ) {
545+ rollupCfg := * chaincfg .OPSepolia ()
546+ rollupCfg .L2ChainID = new (big.Int ).SetUint64 (chainID )
547+ return writeRollupConfig (t , & rollupCfg ), & rollupCfg
548+ }
549+
550+ func writeRollupConfig (t * testing.T , rollupCfg * rollup.Config ) string {
463551 dir := t .TempDir ()
464- j , err := json .Marshal (chaincfg . OPSepolia () )
552+ j , err := json .Marshal (& rollupCfg )
465553 require .NoError (t , err )
466554 cfgFile := dir + "/rollup.json"
467555 require .NoError (t , os .WriteFile (cfgFile , j , 0666 ))
0 commit comments