@@ -32,17 +32,19 @@ import { prepareChainConfig } from '../prepareChainConfig';
3232import { prepareNodeConfig } from '../prepareNodeConfig' ;
3333import { ChainConfig } from '../types/ChainConfig' ;
3434import { CreateRollupParams , RollupCreatorSupportedVersion } from '../types/createRollupTypes' ;
35+ import type { ParentChainId } from '../types/ParentChain' ;
3536import { testConstants } from './constants' ;
3637import {
3738 cleanupCurrentHarnessResources ,
3839 cleanupStaleHarnessContainers ,
3940 cleanupStaleHarnessNetworks ,
4041 createDockerNetwork ,
4142 startL1AnvilContainer ,
42- startL2NitroContainer ,
43+ startNitroContainer ,
4344 waitForRpc ,
4445} from './dockerHelpers' ;
4546import {
47+ bridgeNativeTokenToOrbitChain ,
4648 ContractArtifact ,
4749 configureL2Fees ,
4850 createAccount ,
@@ -73,13 +75,16 @@ type BaseStack<L2Accounts, L3Accounts> = {
7375 upgradeExecutor : Address ;
7476 } ;
7577 l3 : {
78+ rpcUrl : string ;
79+ chain : Chain ;
7680 accounts : L3Accounts ;
7781 timingParams : CustomTimingParams ;
7882 nativeToken : Address ;
7983 rollup : Address ;
8084 bridge : Address ;
8185 sequencerInbox : Address ;
82- upgradeExecutor : Address ;
86+ parentChainUpgradeExecutor : Address ;
87+ childChainUpgradeExecutor : Address ;
8388 batchPoster : Address ;
8489 } ;
8590} ;
@@ -112,6 +117,7 @@ let runtimeDir: string | undefined;
112117let dockerNetworkName : string | undefined ;
113118let l1ContainerName : string | undefined ;
114119let l2ContainerName : string | undefined ;
120+ let l3ContainerName : string | undefined ;
115121let cleanupHookRegistered = false ;
116122let teardownStarted = false ;
117123let l1RpcCachingProxy : RpcCachingProxy | undefined ;
@@ -121,8 +127,11 @@ const NITRO_TESTNODE_VALIDATOR_SIGNER = '0x6A568afe0f82d34759347bb36F14A6bB171d2
121127
122128function prepareNitroRuntimeDir ( runtimeDir : string ) {
123129 chmodSync ( runtimeDir , 0o777 ) ;
124- mkdirSync ( join ( runtimeDir , 'nitro-data' ) , { recursive : true , mode : 0o777 } ) ;
125- chmodSync ( join ( runtimeDir , 'nitro-data' ) , 0o777 ) ;
130+
131+ for ( const dataDir of [ 'nitro-data-l2' , 'nitro-data-l3' ] ) {
132+ mkdirSync ( join ( runtimeDir , dataDir ) , { recursive : true , mode : 0o777 } ) ;
133+ chmodSync ( join ( runtimeDir , dataDir ) , 0o777 ) ;
134+ }
126135}
127136
128137async function getNitroTestnodeStyleValidators (
@@ -174,6 +183,7 @@ export function dehydrateAnvilTestStack(env: AnvilTestStack): InjectedAnvilTestS
174183export function hydrateAnvilTestStack ( env : InjectedAnvilTestStack ) : AnvilTestStack {
175184 const l2Chain = defineChain ( env . l2 . chain ) as RegisteredParentChain ;
176185 registerCustomParentChain ( l2Chain ) ;
186+ const l3Chain = defineChain ( env . l3 . chain ) ;
177187
178188 return {
179189 ...env ,
@@ -187,6 +197,7 @@ export function hydrateAnvilTestStack(env: InjectedAnvilTestStack): AnvilTestSta
187197 } ,
188198 l3 : {
189199 ...env . l3 ,
200+ chain : l3Chain ,
190201 accounts : {
191202 rollupOwner : createAccount ( env . l3 . accounts . rollupOwnerPrivateKey ) ,
192203 tokenBridgeDeployer : createAccount ( env . l3 . accounts . tokenBridgeDeployerPrivateKey ) ,
@@ -223,6 +234,7 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
223234 const l3ChainId = l2ChainId + 1 ;
224235 const l1RpcPort = testConstants . DEFAULT_L1_RPC_PORT ;
225236 const l2RpcPort = testConstants . DEFAULT_L2_RPC_PORT ;
237+ const l3RpcPort = testConstants . DEFAULT_L3_RPC_PORT ;
226238 const anvilImage = testConstants . DEFAULT_ANVIL_IMAGE ;
227239 const nitroImage = testConstants . DEFAULT_NITRO_IMAGE ;
228240 const sepoliaBeaconRpc = testConstants . DEFAULT_SEPOLIA_BEACON_RPC ;
@@ -347,7 +359,11 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
347359 parentChainBeaconRpcUrl : sepoliaBeaconRpc ,
348360 } ) ;
349361
350- if ( l2NodeConfig . node === undefined || l2NodeConfig . node [ 'batch-poster' ] === undefined ) {
362+ if (
363+ l2NodeConfig . node === undefined ||
364+ l2NodeConfig . node [ 'batch-poster' ] === undefined ||
365+ l2NodeConfig . node . staker === undefined
366+ ) {
351367 throw new Error ( 'L2 node config batch poster is undefined' ) ;
352368 }
353369
@@ -360,20 +376,23 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
360376 'wait-for-l1-finality' : false ,
361377 } ;
362378
363- l2NodeConfig . node ! . staker ! . enable = false ;
364- const nodeConfigPath = join ( runtimeDir , 'l2-node-config.json' ) ;
365- writeFileSync ( nodeConfigPath , JSON . stringify ( l2NodeConfig , null , 2 ) , { mode : 0o644 } ) ;
379+ l2NodeConfig . node . staker . enable = false ;
380+
381+ const l2NodeConfigPath = join ( runtimeDir , 'l2-node-config.json' ) ;
382+ writeFileSync ( l2NodeConfigPath , JSON . stringify ( l2NodeConfig , null , 2 ) , { mode : 0o644 } ) ;
366383
367384 // Starting L2 node (Nitro)
368385 console . log ( 'Starting L2 Nitro node...' ) ;
369386 l2ContainerName = `chain-sdk-int-test-l2-${ Date . now ( ) } ` ;
370387
371- startL2NitroContainer ( {
388+ startNitroContainer ( {
372389 containerName : l2ContainerName ,
373390 networkName : dockerNetworkName ,
374- l2RpcPort,
391+ rpcPort : l2RpcPort ,
375392 runtimeDir,
376393 nitroImage,
394+ configFilePath : '/runtime/l2-node-config.json' ,
395+ persistentChainPath : '/runtime/nitro-data-l2' ,
377396 } ) ;
378397
379398 const l2RpcUrl = `http://127.0.0.1:${ l2RpcPort } ` ;
@@ -552,6 +571,97 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
552571 } ) ;
553572 console . log ( 'L3 rollup contracts deployed on L2\n' ) ;
554573
574+ const l3ChainConfig = JSON . parse ( l3RollupConfig . chainConfig ) as ChainConfig ;
575+ const l3NodeConfig = prepareNodeConfig ( {
576+ chainName : 'Chain SDK Int Test L3' ,
577+ chainConfig : l3ChainConfig ,
578+ coreContracts : l3Rollup . coreContracts ,
579+ batchPosterPrivateKey : harnessDeployer . privateKey ,
580+ validatorPrivateKey : harnessDeployer . privateKey ,
581+ stakeToken : l3RollupConfig . stakeToken ,
582+ parentChainId : l2ChainId as ParentChainId ,
583+ parentChainIsArbitrum : true ,
584+ parentChainRpcUrl : `http://${ l2ContainerName } :8449` ,
585+ } ) ;
586+
587+ if (
588+ l3NodeConfig . node === undefined ||
589+ l3NodeConfig . node [ 'batch-poster' ] === undefined ||
590+ l3NodeConfig . node . staker === undefined
591+ ) {
592+ throw new Error ( 'L3 node config is undefined' ) ;
593+ }
594+
595+ // The test harness only needs a local L3 sequencer/read node.
596+ // Disable services that require extra parent-chain plumbing.
597+ l3NodeConfig . node [ 'batch-poster' ] . enable = false ;
598+ l3NodeConfig . node . staker . enable = false ;
599+ if ( l3ChainConfig . arbitrum . DataAvailabilityCommittee ) {
600+ delete l3NodeConfig . node [ 'data-availability' ] ?. [ 'rpc-aggregator' ] ;
601+ }
602+
603+ const l3NodeConfigPath = join ( runtimeDir , 'l3-node-config.json' ) ;
604+ writeFileSync ( l3NodeConfigPath , JSON . stringify ( l3NodeConfig , null , 2 ) , { mode : 0o644 } ) ;
605+
606+ // Starting L3 node (Nitro)
607+ console . log ( 'Starting L3 Nitro node...' ) ;
608+ l3ContainerName = `chain-sdk-int-test-l3-${ Date . now ( ) } ` ;
609+
610+ startNitroContainer ( {
611+ containerName : l3ContainerName ,
612+ networkName : dockerNetworkName ,
613+ rpcPort : l3RpcPort ,
614+ runtimeDir,
615+ nitroImage,
616+ configFilePath : '/runtime/l3-node-config.json' ,
617+ persistentChainPath : '/runtime/nitro-data-l3' ,
618+ } ) ;
619+
620+ const l3RpcUrl = `http://127.0.0.1:${ l3RpcPort } ` ;
621+ const l3Chain = defineChain ( {
622+ id : l3ChainId ,
623+ network : 'chain-sdk-int-test-l3' ,
624+ name : 'Chain SDK Int Test L3' ,
625+ nativeCurrency : { name : 'Orbit Test Token' , symbol : 'ORBT' , decimals : 18 } ,
626+ rpcUrls : {
627+ default : { http : [ l3RpcUrl ] } ,
628+ public : { http : [ l3RpcUrl ] } ,
629+ } ,
630+ testnet : true ,
631+ } ) ;
632+
633+ await waitForRpc ( {
634+ rpcUrl : l3RpcUrl ,
635+ timeoutMs : 60_000 ,
636+ failIfContainerExited : l3ContainerName ,
637+ } ) ;
638+ console . log ( 'L3 Nitro node is ready\n' ) ;
639+ const l3Client = createPublicClient ( {
640+ chain : l3Chain ,
641+ transport : http ( l3RpcUrl ) ,
642+ } ) ;
643+
644+ await (
645+ await customGasToken . deposit ( {
646+ value : parseEther ( '100' ) ,
647+ ...testConstants . LOW_L2_FEE_OVERRIDES ,
648+ } )
649+ ) . wait ( ) ;
650+
651+ console . log ( 'Funding deployer on L3...' ) ;
652+ await bridgeNativeTokenToOrbitChain ( {
653+ parentPublicClient : l2Client ,
654+ parentWalletClient : l2WalletClient ,
655+ childPublicClient : l3Client ,
656+ depositor : harnessDeployer ,
657+ inbox : l3Rollup . coreContracts . inbox ,
658+ nativeToken : customGasToken . address as Address ,
659+ amount : parseEther ( '100' ) ,
660+ } ) ;
661+ console . log ( 'Deployer funded on L3\n' ) ;
662+
663+ const l3ChildChainUpgradeExecutor = l3Rollup . coreContracts . upgradeExecutor ;
664+
555665 initializedEnv = {
556666 l1 : {
557667 rpcUrl : l1RpcUrl ,
@@ -569,6 +679,8 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
569679 upgradeExecutor : l2Rollup . coreContracts . upgradeExecutor ,
570680 } ,
571681 l3 : {
682+ rpcUrl : l3RpcUrl ,
683+ chain : l3Chain ,
572684 accounts : {
573685 rollupOwner : harnessDeployer ,
574686 tokenBridgeDeployer : harnessDeployer ,
@@ -578,7 +690,8 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
578690 rollup : l3Rollup . coreContracts . rollup ,
579691 bridge : l3Rollup . coreContracts . bridge ,
580692 sequencerInbox : l3Rollup . coreContracts . sequencerInbox ,
581- upgradeExecutor : l3Rollup . coreContracts . upgradeExecutor ,
693+ parentChainUpgradeExecutor : l3Rollup . coreContracts . upgradeExecutor ,
694+ childChainUpgradeExecutor : l3ChildChainUpgradeExecutor ,
582695 batchPoster : harnessDeployer . address ,
583696 } ,
584697 } ;
@@ -615,12 +728,14 @@ export function teardownAnvilTestStack() {
615728 }
616729
617730 cleanupCurrentHarnessResources ( {
731+ l3ContainerName : l3ContainerName ,
618732 l2ContainerName : l2ContainerName ,
619733 l1ContainerName : l1ContainerName ,
620734 dockerNetworkName : dockerNetworkName ,
621735 runtimeDir : runtimeDir ,
622736 } ) ;
623737
738+ l3ContainerName = undefined ;
624739 l2ContainerName = undefined ;
625740 l1ContainerName = undefined ;
626741 dockerNetworkName = undefined ;
0 commit comments