Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
4e13b20f
Unverified
Commit
4e13b20f
authored
Oct 30, 2024
by
Matthew Slipper
Committed by
GitHub
Oct 30, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-deployer: Reduce test code duplication, put test funcs first (#12751)
parent
451224fe
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
506 additions
and
586 deletions
+506
-586
apply_test.go
op-deployer/pkg/deployer/integration_test/apply_test.go
+506
-586
No files found.
op-deployer/pkg/deployer/integration_test/apply_test.go
View file @
4e13b20f
...
@@ -14,10 +14,9 @@ import (
...
@@ -14,10 +14,9 @@ import (
"testing"
"testing"
"time"
"time"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum-optimism/optimism/op-chain-ops/script"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-service/testutils/anvil"
"github.com/ethereum-optimism/optimism/op-service/testutils/anvil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
...
@@ -156,336 +155,238 @@ func TestEndToEndApply(t *testing.T) {
...
@@ -156,336 +155,238 @@ func TestEndToEndApply(t *testing.T) {
})
})
}
}
func
localArtifactsLocator
(
t
*
testing
.
T
)
*
opcm
.
ArtifactsLocator
{
func
TestApplyExistingOPCM
(
t
*
testing
.
T
)
{
_
,
testFilename
,
_
,
ok
:=
runtime
.
Caller
(
0
)
anvil
.
Test
(
t
)
require
.
Truef
(
t
,
ok
,
"failed to get test filename"
)
monorepoDir
:=
path
.
Join
(
path
.
Dir
(
testFilename
),
".."
,
".."
,
".."
,
".."
)
artifactsDir
:=
path
.
Join
(
monorepoDir
,
"packages"
,
"contracts-bedrock"
,
"forge-artifacts"
)
artifactsURL
,
err
:=
url
.
Parse
(
fmt
.
Sprintf
(
"file://%s"
,
artifactsDir
))
require
.
NoError
(
t
,
err
)
loc
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
}
return
loc
}
func
createEnv
(
forkRPCUrl
:=
os
.
Getenv
(
"SEPOLIA_RPC_URL"
)
t
*
testing
.
T
,
if
forkRPCUrl
==
""
{
ctx
context
.
Context
,
t
.
Skip
(
"no fork RPC URL provided"
)
lgr
log
.
Logger
,
l1Client
*
ethclient
.
Client
,
bcaster
broadcaster
.
Broadcaster
,
deployerAddr
common
.
Address
,
)
(
*
pipeline
.
Env
,
pipeline
.
ArtifactsBundle
,
*
script
.
Host
)
{
_
,
testFilename
,
_
,
ok
:=
runtime
.
Caller
(
0
)
require
.
Truef
(
t
,
ok
,
"failed to get test filename"
)
monorepoDir
:=
path
.
Join
(
path
.
Dir
(
testFilename
),
".."
,
".."
,
".."
,
".."
)
artifactsDir
:=
path
.
Join
(
monorepoDir
,
"packages"
,
"contracts-bedrock"
,
"forge-artifacts"
)
artifactsURL
,
err
:=
url
.
Parse
(
fmt
.
Sprintf
(
"file://%s"
,
artifactsDir
))
require
.
NoError
(
t
,
err
)
artifactsLocator
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
}
}
artifactsFS
,
cleanupArtifacts
,
err
:=
pipeline
.
DownloadArtifacts
(
ctx
,
artifactsLocator
,
pipeline
.
NoopDownloadProgressor
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
require
.
NoError
(
t
,
err
)
defer
func
()
{
require
.
NoError
(
t
,
cleanupArtifacts
())
}()
host
,
err
:=
pipeline
.
DefaultScriptHost
(
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Minute
)
bcaster
,
defer
cancel
()
runner
,
err
:=
anvil
.
New
(
forkRPCUrl
,
lgr
,
lgr
,
deployerAddr
,
artifactsFS
,
0
,
)
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
env
:=
&
pipeline
.
Env
{
require
.
NoError
(
t
,
runner
.
Start
(
ctx
))
StateWriter
:
pipeline
.
NoopStateWriter
(),
t
.
Cleanup
(
func
()
{
L1ScriptHost
:
host
,
require
.
NoError
(
t
,
runner
.
Stop
())
L1Client
:
l1Client
,
})
Broadcaster
:
bcaster
,
Deployer
:
deployerAddr
,
Logger
:
lgr
,
}
bundle
:=
pipeline
.
ArtifactsBundle
{
l1Client
,
err
:=
ethclient
.
Dial
(
runner
.
RPCUrl
())
L1
:
artifactsFS
,
require
.
NoError
(
t
,
err
)
L2
:
artifactsFS
,
}
return
env
,
bundle
,
host
l1ChainID
:=
big
.
NewInt
(
11155111
)
}
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
require
.
NoError
(
t
,
err
)
// index 0 from Anvil's test set
priv
,
err
:=
crypto
.
HexToECDSA
(
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
require
.
NoError
(
t
,
err
)
signer
:=
opcrypto
.
SignerFnFromBind
(
opcrypto
.
PrivateKeySignerFn
(
priv
,
l1ChainID
))
deployerAddr
:=
common
.
HexToAddress
(
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
func
addrFor
(
t
*
testing
.
T
,
dk
*
devkeys
.
MnemonicDevKeys
,
key
devkeys
.
Key
)
common
.
Address
{
l2ChainID
:=
uint256
.
NewInt
(
1
)
addr
,
err
:=
dk
.
Address
(
key
)
bcaster
,
err
:=
broadcaster
.
NewKeyedBroadcaster
(
broadcaster
.
KeyedBroadcasterOpts
{
Logger
:
lgr
,
ChainID
:
l1ChainID
,
Client
:
l1Client
,
Signer
:
signer
,
From
:
deployerAddr
,
})
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
return
addr
}
func
newIntent
(
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
l1Client
,
bcaster
,
deployerAddr
)
t
*
testing
.
T
,
l1ChainID
*
big
.
Int
,
dk
*
devkeys
.
MnemonicDevKeys
,
l2ChainID
*
uint256
.
Int
,
l1Loc
*
opcm
.
ArtifactsLocator
,
l2Loc
*
opcm
.
ArtifactsLocator
,
)
(
*
state
.
Intent
,
*
state
.
State
)
{
intent
:=
&
state
.
Intent
{
DeploymentStrategy
:
state
.
DeploymentStrategyLive
,
L1ChainID
:
l1ChainID
.
Uint64
(),
SuperchainRoles
:
&
state
.
SuperchainRoles
{
ProxyAdminOwner
:
addrFor
(
t
,
dk
,
devkeys
.
L1ProxyAdminOwnerRole
.
Key
(
l1ChainID
)),
ProtocolVersionsOwner
:
addrFor
(
t
,
dk
,
devkeys
.
SuperchainDeployerKey
.
Key
(
l1ChainID
)),
Guardian
:
addrFor
(
t
,
dk
,
devkeys
.
SuperchainConfigGuardianKey
.
Key
(
l1ChainID
)),
},
FundDevAccounts
:
true
,
L1ContractsLocator
:
l1Loc
,
L2ContractsLocator
:
l2Loc
,
Chains
:
[]
*
state
.
ChainIntent
{
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID
),
},
}
st
:=
&
state
.
State
{
Version
:
1
,
}
return
intent
,
st
}
func
newChainIntent
(
t
*
testing
.
T
,
dk
*
devkeys
.
MnemonicDevKeys
,
l1ChainID
*
big
.
Int
,
l2ChainID
*
uint256
.
Int
)
*
state
.
ChainIntent
{
intent
,
st
:=
newIntent
(
return
&
state
.
ChainIntent
{
t
,
ID
:
l2ChainID
.
Bytes32
(),
l1ChainID
,
BaseFeeVaultRecipient
:
addrFor
(
t
,
dk
,
devkeys
.
BaseFeeVaultRecipientRole
.
Key
(
l1ChainID
)),
dk
,
L1FeeVaultRecipient
:
addrFor
(
t
,
dk
,
devkeys
.
L1FeeVaultRecipientRole
.
Key
(
l1ChainID
)),
l2ChainID
,
SequencerFeeVaultRecipient
:
addrFor
(
t
,
dk
,
devkeys
.
SequencerFeeVaultRecipientRole
.
Key
(
l1ChainID
)),
opcm
.
DefaultL1ContractsLocator
,
Eip1559Denominator
:
50
,
opcm
.
DefaultL2ContractsLocator
,
Eip1559Elasticity
:
6
,
)
Roles
:
state
.
ChainRoles
{
L1ProxyAdminOwner
:
addrFor
(
t
,
dk
,
devkeys
.
L2ProxyAdminOwnerRole
.
Key
(
l1ChainID
)),
L2ProxyAdminOwner
:
addrFor
(
t
,
dk
,
devkeys
.
L2ProxyAdminOwnerRole
.
Key
(
l1ChainID
)),
SystemConfigOwner
:
addrFor
(
t
,
dk
,
devkeys
.
SystemConfigOwner
.
Key
(
l1ChainID
)),
UnsafeBlockSigner
:
addrFor
(
t
,
dk
,
devkeys
.
SequencerP2PRole
.
Key
(
l1ChainID
)),
Batcher
:
addrFor
(
t
,
dk
,
devkeys
.
BatcherRole
.
Key
(
l1ChainID
)),
Proposer
:
addrFor
(
t
,
dk
,
devkeys
.
ProposerRole
.
Key
(
l1ChainID
)),
Challenger
:
addrFor
(
t
,
dk
,
devkeys
.
ChallengerRole
.
Key
(
l1ChainID
)),
},
}
}
type
codeGetter
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
func
ethClientCodeGetter
(
ctx
context
.
Context
,
client
*
ethclient
.
Client
)
codeGetter
{
validateOPChainDeployment
(
t
,
ethClientCodeGetter
(
ctx
,
l1Client
),
st
,
intent
)
return
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
{
code
,
err
:=
client
.
CodeAt
(
ctx
,
addr
,
nil
)
require
.
NoError
(
t
,
err
)
return
code
}
}
}
func
stateDumpCodeGetter
(
st
*
state
.
State
)
codeGetter
{
func
TestL2BlockTimeOverride
(
t
*
testing
.
T
)
{
return
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
{
op_e2e
.
InitParallel
(
t
)
acc
,
ok
:=
st
.
L1StateDump
.
Data
.
Accounts
[
addr
]
kurtosisutil
.
Test
(
t
)
require
.
True
(
t
,
ok
,
"no account found for address %s"
,
addr
)
return
acc
.
Code
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
intent
.
GlobalDeployOverrides
=
map
[
string
]
interface
{}{
"l2BlockTime"
:
float64
(
3
),
}
}
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
cfg
,
err
:=
state
.
CombineDeployConfig
(
intent
,
intent
.
Chains
[
0
],
st
,
st
.
Chains
[
0
])
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
uint64
(
3
),
cfg
.
L2InitializationConfig
.
L2CoreDeployConfig
.
L2BlockTime
,
"L2 block time should be 3 seconds"
)
}
}
func
validateSuperchainDeployment
(
t
*
testing
.
T
,
st
*
state
.
State
,
cg
codeGetter
)
{
func
TestApplyGenesisStrategy
(
t
*
testing
.
T
)
{
addrs
:=
[]
struct
{
op_e2e
.
InitParallel
(
t
)
name
string
addr
common
.
Address
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
}{
defer
cancel
()
{
"SuperchainProxyAdmin"
,
st
.
SuperchainDeployment
.
ProxyAdminAddress
},
{
"SuperchainConfigProxy"
,
st
.
SuperchainDeployment
.
SuperchainConfigProxyAddress
},
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
{
"SuperchainConfigImpl"
,
st
.
SuperchainDeployment
.
SuperchainConfigImplAddress
},
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
{
"ProtocolVersionsProxy"
,
st
.
SuperchainDeployment
.
ProtocolVersionsProxyAddress
},
{
"ProtocolVersionsImpl"
,
st
.
SuperchainDeployment
.
ProtocolVersionsImplAddress
},
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
{
"OpcmProxy"
,
st
.
ImplementationsDeployment
.
OpcmProxyAddress
},
ctx
,
{
"PreimageOracleSingleton"
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
},
env
,
{
"MipsSingleton"
,
st
.
ImplementationsDeployment
.
MipsSingletonAddress
},
bundle
,
}
intent
,
for
_
,
addr
:=
range
addrs
{
st
,
t
.
Run
(
addr
.
name
,
func
(
t
*
testing
.
T
)
{
))
code
:=
cg
(
t
,
addr
.
addr
)
require
.
NotEmpty
(
t
,
code
,
"contract %s at %s has no code"
,
addr
.
name
,
addr
.
addr
)
cg
:=
stateDumpCodeGetter
(
st
)
validateSuperchainDeployment
(
t
,
st
,
cg
)
for
i
:=
range
intent
.
Chains
{
t
.
Run
(
fmt
.
Sprintf
(
"chain-%d"
,
i
),
func
(
t
*
testing
.
T
)
{
validateOPChainDeployment
(
t
,
cg
,
st
,
intent
)
})
})
}
}
}
}
func
validateOPChainDeployment
(
t
*
testing
.
T
,
cg
codeGetter
,
st
*
state
.
State
,
intent
*
state
.
Intent
)
{
func
TestProofParamOverrides
(
t
*
testing
.
T
)
{
// Validate that the implementation addresses are always set, even in subsequent deployments
op_e2e
.
InitParallel
(
t
)
// that pull from an existing OPCM deployment.
implAddrs
:=
[]
struct
{
name
string
addr
common
.
Address
}{
{
"DelayedWETHImplAddress"
,
st
.
ImplementationsDeployment
.
DelayedWETHImplAddress
},
{
"OptimismPortalImplAddress"
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
},
{
"SystemConfigImplAddress"
,
st
.
ImplementationsDeployment
.
SystemConfigImplAddress
},
{
"L1CrossDomainMessengerImplAddress"
,
st
.
ImplementationsDeployment
.
L1CrossDomainMessengerImplAddress
},
{
"L1ERC721BridgeImplAddress"
,
st
.
ImplementationsDeployment
.
L1ERC721BridgeImplAddress
},
{
"L1StandardBridgeImplAddress"
,
st
.
ImplementationsDeployment
.
L1StandardBridgeImplAddress
},
{
"OptimismMintableERC20FactoryImplAddress"
,
st
.
ImplementationsDeployment
.
OptimismMintableERC20FactoryImplAddress
},
{
"DisputeGameFactoryImplAddress"
,
st
.
ImplementationsDeployment
.
DisputeGameFactoryImplAddress
},
{
"MipsSingletonAddress"
,
st
.
ImplementationsDeployment
.
MipsSingletonAddress
},
{
"PreimageOracleSingletonAddress"
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
},
}
for
_
,
addr
:=
range
implAddrs
{
require
.
NotEmpty
(
t
,
addr
.
addr
,
"%s should be set"
,
addr
.
name
)
code
:=
cg
(
t
,
addr
.
addr
)
require
.
NotEmpty
(
t
,
code
,
"contract %s at %s has no code"
,
addr
.
name
,
addr
.
addr
)
}
for
i
,
chainState
:=
range
st
.
Chains
{
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
chainAddrs
:=
[]
struct
{
defer
cancel
()
name
string
addr
common
.
Address
}{
{
"ProxyAdminAddress"
,
chainState
.
ProxyAdminAddress
},
{
"AddressManagerAddress"
,
chainState
.
AddressManagerAddress
},
{
"L1ERC721BridgeProxyAddress"
,
chainState
.
L1ERC721BridgeProxyAddress
},
{
"SystemConfigProxyAddress"
,
chainState
.
SystemConfigProxyAddress
},
{
"OptimismMintableERC20FactoryProxyAddress"
,
chainState
.
OptimismMintableERC20FactoryProxyAddress
},
{
"L1StandardBridgeProxyAddress"
,
chainState
.
L1StandardBridgeProxyAddress
},
{
"L1CrossDomainMessengerProxyAddress"
,
chainState
.
L1CrossDomainMessengerProxyAddress
},
{
"OptimismPortalProxyAddress"
,
chainState
.
OptimismPortalProxyAddress
},
{
"DisputeGameFactoryProxyAddress"
,
chainState
.
DisputeGameFactoryProxyAddress
},
{
"AnchorStateRegistryProxyAddress"
,
chainState
.
AnchorStateRegistryProxyAddress
},
{
"FaultDisputeGameAddress"
,
chainState
.
FaultDisputeGameAddress
},
{
"PermissionedDisputeGameAddress"
,
chainState
.
PermissionedDisputeGameAddress
},
{
"DelayedWETHPermissionedGameProxyAddress"
,
chainState
.
DelayedWETHPermissionedGameProxyAddress
},
// {"DelayedWETHPermissionlessGameProxyAddress", chainState.DelayedWETHPermissionlessGameProxyAddress},
}
for
_
,
addr
:=
range
chainAddrs
{
// TODO Delete this `if`` block once FaultDisputeGameAddress is deployed.
if
addr
.
name
==
"FaultDisputeGameAddress"
{
continue
}
code
:=
cg
(
t
,
addr
.
addr
)
require
.
NotEmpty
(
t
,
code
,
"contract %s at %s for chain %s has no code"
,
addr
.
name
,
addr
.
addr
,
chainState
.
ID
)
}
alloc
:=
chainState
.
Allocs
.
Data
.
Accounts
chainIntent
:=
intent
.
Chains
[
i
]
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
BaseFeeVaultAddr
,
chainIntent
.
BaseFeeVaultRecipient
)
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
L1FeeVaultAddr
,
chainIntent
.
L1FeeVaultRecipient
)
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
SequencerFeeVaultAddr
,
chainIntent
.
SequencerFeeVaultRecipient
)
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
OptimismMintableERC721FactoryAddr
,
common
.
BigToHash
(
new
(
big
.
Int
)
.
SetUint64
(
intent
.
L1ChainID
)))
// ownership slots
var
addrAsSlot
common
.
Hash
addrAsSlot
.
SetBytes
(
chainIntent
.
Roles
.
L1ProxyAdminOwner
.
Bytes
())
// slot 0
ownerSlot
:=
common
.
Hash
{}
checkStorageSlot
(
t
,
alloc
,
predeploys
.
ProxyAdminAddr
,
ownerSlot
,
addrAsSlot
)
var
defaultGovOwner
common
.
Hash
defaultGovOwner
.
SetBytes
(
common
.
HexToAddress
(
"0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAdDEad"
)
.
Bytes
())
checkStorageSlot
(
t
,
alloc
,
predeploys
.
GovernanceTokenAddr
,
common
.
Hash
{
31
:
0x0a
},
defaultGovOwner
)
require
.
Equal
(
t
,
int
(
chainIntent
.
Eip1559Denominator
),
50
,
"EIP1559Denominator should be set"
)
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
require
.
Equal
(
t
,
int
(
chainIntent
.
Eip1559Elasticity
),
6
,
"EIP1559Elasticity should be set"
)
intent
.
GlobalDeployOverrides
=
map
[
string
]
any
{
"withdrawalDelaySeconds"
:
standard
.
WithdrawalDelaySeconds
+
1
,
"minProposalSizeBytes"
:
standard
.
MinProposalSizeBytes
+
1
,
"challengePeriodSeconds"
:
standard
.
ChallengePeriodSeconds
+
1
,
"proofMaturityDelaySeconds"
:
standard
.
ProofMaturityDelaySeconds
+
1
,
"disputeGameFinalityDelaySeconds"
:
standard
.
DisputeGameFinalityDelaySeconds
+
1
,
"mipsVersion"
:
standard
.
MIPSVersion
+
1
,
"disputeGameType"
:
standard
.
DisputeGameType
,
// This must be set to the permissioned game
"disputeAbsolutePrestate"
:
common
.
Hash
{
'A'
,
'B'
,
'S'
,
'O'
,
'L'
,
'U'
,
'T'
,
'E'
},
"disputeMaxGameDepth"
:
standard
.
DisputeMaxGameDepth
+
1
,
"disputeSplitDepth"
:
standard
.
DisputeSplitDepth
+
1
,
"disputeClockExtension"
:
standard
.
DisputeClockExtension
+
1
,
"disputeMaxClockDuration"
:
standard
.
DisputeMaxClockDuration
+
1
,
"dangerouslyAllowCustomDisputeParameters"
:
true
,
}
}
}
func
getEIP1967ImplementationAddress
(
t
*
testing
.
T
,
allocations
types
.
GenesisAlloc
,
proxyAddress
common
.
Address
)
common
.
Address
{
storage
:=
allocations
[
proxyAddress
]
.
Storage
storageValue
:=
storage
[
genesis
.
ImplementationSlot
]
require
.
NotEmpty
(
t
,
storageValue
,
"Implementation address for %s should be set"
,
proxyAddress
)
return
common
.
HexToAddress
(
storageValue
.
Hex
())
}
type
bytesMarshaler
interface
{
Bytes
()
[]
byte
}
func
checkImmutableBehindProxy
(
t
*
testing
.
T
,
allocations
types
.
GenesisAlloc
,
proxyContract
common
.
Address
,
thing
bytesMarshaler
)
{
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
implementationAddress
:=
getEIP1967ImplementationAddress
(
t
,
allocations
,
proxyContract
)
ctx
,
checkImmutable
(
t
,
allocations
,
implementationAddress
,
thing
)
env
,
}
bundle
,
intent
,
st
,
))
func
checkImmutable
(
t
*
testing
.
T
,
allocations
types
.
GenesisAlloc
,
implementationAddress
common
.
Address
,
thing
bytesMarshaler
)
{
allocs
:=
st
.
L1StateDump
.
Data
.
Accounts
account
,
ok
:=
allocations
[
implementationAddress
]
chainState
:=
st
.
Chains
[
0
]
require
.
True
(
t
,
ok
,
"%s not found in allocations"
,
implementationAddress
)
require
.
NotEmpty
(
t
,
account
.
Code
,
"%s should have code"
,
implementationAddress
)
require
.
True
(
t
,
bytes
.
Contains
(
account
.
Code
,
thing
.
Bytes
()),
"%s code should contain %s immutable"
,
implementationAddress
,
hex
.
EncodeToString
(
thing
.
Bytes
()),
)
}
func
checkStorageSlot
(
t
*
testing
.
T
,
allocs
types
.
GenesisAlloc
,
address
common
.
Address
,
slot
common
.
Hash
,
expected
common
.
Hash
)
{
uint64Caster
:=
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
{
account
,
ok
:=
allocs
[
address
]
return
common
.
BigToHash
(
new
(
big
.
Int
)
.
SetUint64
(
val
.
(
uint64
)))
require
.
True
(
t
,
ok
,
"account not found for address %s"
,
address
)
value
,
ok
:=
account
.
Storage
[
slot
]
if
expected
==
(
common
.
Hash
{})
{
require
.
False
(
t
,
ok
,
"slot %s for account %s should not be set"
,
slot
,
address
)
return
}
}
require
.
True
(
t
,
ok
,
"slot %s not found for account %s"
,
slot
,
address
)
require
.
Equal
(
t
,
expected
,
value
,
"slot %s for account %s should be %s"
,
slot
,
address
,
expected
)
}
func
TestApplyExistingOPCM
(
t
*
testing
.
T
)
{
anvil
.
Test
(
t
)
forkRPCUrl
:=
os
.
Getenv
(
"SEPOLIA_RPC_URL"
)
tests
:=
[]
struct
{
if
forkRPCUrl
==
""
{
name
string
t
.
Skip
(
"no fork RPC URL provided"
)
caster
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
address
common
.
Address
}{
{
"withdrawalDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
DelayedWETHImplAddress
,
},
{
"minProposalSizeBytes"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
,
},
{
"challengePeriodSeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
,
},
{
"proofMaturityDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
,
},
{
"disputeGameFinalityDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
,
},
{
"disputeAbsolutePrestate"
,
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
{
return
val
.
(
common
.
Hash
)
},
chainState
.
PermissionedDisputeGameAddress
,
},
{
"disputeMaxGameDepth"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
},
{
"disputeSplitDepth"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
},
{
"disputeClockExtension"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
},
{
"disputeMaxClockDuration"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
checkImmutable
(
t
,
allocs
,
tt
.
address
,
tt
.
caster
(
t
,
intent
.
GlobalDeployOverrides
[
tt
.
name
]))
})
}
}
}
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
func
TestInteropDeployment
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
ctx
,
cancel
:=
context
.
With
Timeout
(
context
.
Background
(),
5
*
time
.
Minute
)
ctx
,
cancel
:=
context
.
With
Cancel
(
context
.
Background
()
)
defer
cancel
()
defer
cancel
()
runner
,
err
:=
anvil
.
New
(
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
forkRPCUrl
,
intent
.
UseInterop
=
true
lgr
,
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
runner
.
Start
(
ctx
))
t
.
Cleanup
(
func
()
{
require
.
NoError
(
t
,
runner
.
Stop
())
})
l1Client
,
err
:=
ethclient
.
Dial
(
runner
.
RPCUrl
())
require
.
NoError
(
t
,
err
)
l1ChainID
:=
big
.
NewInt
(
11155111
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
require
.
NoError
(
t
,
err
)
// index 0 from Anvil's test set
priv
,
err
:=
crypto
.
HexToECDSA
(
"ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
)
require
.
NoError
(
t
,
err
)
signer
:=
opcrypto
.
SignerFnFromBind
(
opcrypto
.
PrivateKeySignerFn
(
priv
,
l1ChainID
))
deployerAddr
:=
common
.
HexToAddress
(
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
)
l2ChainID
:=
uint256
.
NewInt
(
1
)
bcaster
,
err
:=
broadcaster
.
NewKeyedBroadcaster
(
broadcaster
.
KeyedBroadcasterOpts
{
Logger
:
lgr
,
ChainID
:
l1ChainID
,
Client
:
l1Client
,
Signer
:
signer
,
From
:
deployerAddr
,
})
require
.
NoError
(
t
,
err
)
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
l1Client
,
bcaster
,
deployerAddr
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID
,
opcm
.
DefaultL1ContractsLocator
,
opcm
.
DefaultL2ContractsLocator
,
)
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
ctx
,
...
@@ -495,253 +396,98 @@ func TestApplyExistingOPCM(t *testing.T) {
...
@@ -495,253 +396,98 @@ func TestApplyExistingOPCM(t *testing.T) {
st
,
st
,
))
))
validateOPChainDeployment
(
t
,
ethClientCodeGetter
(
ctx
,
l1Client
),
st
,
intent
)
chainState
:=
st
.
Chains
[
0
]
depManagerSlot
:=
common
.
HexToHash
(
"0x1708e077affb93e89be2665fb0fb72581be66f84dc00d25fed755ae911905b1c"
)
checkImmutable
(
t
,
st
.
L1StateDump
.
Data
.
Accounts
,
st
.
ImplementationsDeployment
.
SystemConfigImplAddress
,
depManagerSlot
)
proxyAdminOwnerHash
:=
common
.
BytesToHash
(
intent
.
Chains
[
0
]
.
Roles
.
L1ProxyAdminOwner
.
Bytes
())
checkStorageSlot
(
t
,
st
.
L1StateDump
.
Data
.
Accounts
,
chainState
.
SystemConfigProxyAddress
,
depManagerSlot
,
proxyAdminOwnerHash
)
}
}
func
Test
L2BlockTimeOverride
(
t
*
testing
.
T
)
{
func
Test
InvalidL2Genesis
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
op_e2e
.
InitParallel
(
t
)
kurtosisutil
.
Test
(
t
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
defer
cancel
()
enclaveCtx
:=
kurtosisutil
.
StartEnclave
(
t
,
ctx
,
lgr
,
"github.com/ethpandaops/ethereum-package"
,
TestParams
)
service
,
err
:=
enclaveCtx
.
GetServiceContext
(
"el-1-geth-lighthouse"
)
require
.
NoError
(
t
,
err
)
ip
:=
service
.
GetMaybePublicIPAddress
()
ports
:=
service
.
GetPublicPorts
()
rpcURL
:=
fmt
.
Sprintf
(
"http://%s:%d"
,
ip
,
ports
[
"rpc"
]
.
GetNumber
())
l1Client
,
err
:=
ethclient
.
Dial
(
rpcURL
)
require
.
NoError
(
t
,
err
)
depKey
:=
new
(
deployerKey
)
depKey
:=
new
(
deployerKey
)
l1ChainID
:=
big
.
NewInt
(
77799777
)
l1ChainID
:=
big
.
NewInt
(
77799777
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
pk
,
err
:=
dk
.
Secret
(
depKey
)
require
.
NoError
(
t
,
err
)
signer
:=
opcrypto
.
SignerFnFromBind
(
opcrypto
.
PrivateKeySignerFn
(
pk
,
l1ChainID
))
l2ChainID
:=
uint256
.
NewInt
(
1
)
l2ChainID
1
:=
uint256
.
NewInt
(
1
)
deployerAddr
,
err
:=
dk
.
Address
(
depKey
)
deployerAddr
,
err
:=
dk
.
Address
(
depKey
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
loc
:=
localArtifactsLocator
(
t
)
loc
:=
localArtifactsLocator
(
t
)
bcaster
,
err
:=
broadcaster
.
NewKeyedBroadcaster
(
broadcaster
.
KeyedBroadcasterOpts
{
// these tests were generated by grepping all usages of the deploy
Logger
:
lgr
,
// config in L2Genesis.s.sol.
ChainID
:
l1ChainID
,
Client
:
l1Client
,
Signer
:
signer
,
From
:
deployerAddr
,
})
require
.
NoError
(
t
,
err
)
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
l1Client
,
bcaster
,
deployerAddr
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID
,
loc
,
loc
,
)
intent
.
GlobalDeployOverrides
=
map
[
string
]
interface
{}{
"l2BlockTime"
:
float64
(
3
),
}
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
chainIntent
,
err
:=
intent
.
Chain
(
l2ChainID
.
Bytes32
())
require
.
NoError
(
t
,
err
)
chainState
,
err
:=
st
.
Chain
(
l2ChainID
.
Bytes32
())
require
.
NoError
(
t
,
err
)
cfg
,
err
:=
state
.
CombineDeployConfig
(
intent
,
chainIntent
,
st
,
chainState
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
uint64
(
3
),
cfg
.
L2InitializationConfig
.
L2CoreDeployConfig
.
L2BlockTime
,
"L2 block time should be 3 seconds"
)
}
func
TestApplyGenesisStrategy
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
depKey
:=
new
(
deployerKey
)
l1ChainID
:=
big
.
NewInt
(
77799777
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
require
.
NoError
(
t
,
err
)
l2ChainID1
:=
uint256
.
NewInt
(
1
)
l2ChainID2
:=
uint256
.
NewInt
(
2
)
deployerAddr
,
err
:=
dk
.
Address
(
depKey
)
require
.
NoError
(
t
,
err
)
loc
:=
localArtifactsLocator
(
t
)
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
nil
,
broadcaster
.
NoopBroadcaster
(),
deployerAddr
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID1
,
loc
,
loc
)
intent
.
Chains
=
append
(
intent
.
Chains
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID2
))
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
cg
:=
stateDumpCodeGetter
(
st
)
validateSuperchainDeployment
(
t
,
st
,
cg
)
for
i
:=
range
intent
.
Chains
{
t
.
Run
(
fmt
.
Sprintf
(
"chain-%d"
,
i
),
func
(
t
*
testing
.
T
)
{
validateOPChainDeployment
(
t
,
cg
,
st
,
intent
)
})
}
}
func
TestProofParamOverrides
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
depKey
:=
new
(
deployerKey
)
l1ChainID
:=
big
.
NewInt
(
77799777
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
require
.
NoError
(
t
,
err
)
l2ChainID1
:=
uint256
.
NewInt
(
1
)
deployerAddr
,
err
:=
dk
.
Address
(
depKey
)
require
.
NoError
(
t
,
err
)
loc
:=
localArtifactsLocator
(
t
)
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
nil
,
broadcaster
.
NoopBroadcaster
(),
deployerAddr
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID1
,
loc
,
loc
)
intent
.
Chains
=
append
(
intent
.
Chains
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID1
))
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
intent
.
GlobalDeployOverrides
=
map
[
string
]
any
{
"withdrawalDelaySeconds"
:
standard
.
WithdrawalDelaySeconds
+
1
,
"minProposalSizeBytes"
:
standard
.
MinProposalSizeBytes
+
1
,
"challengePeriodSeconds"
:
standard
.
ChallengePeriodSeconds
+
1
,
"proofMaturityDelaySeconds"
:
standard
.
ProofMaturityDelaySeconds
+
1
,
"disputeGameFinalityDelaySeconds"
:
standard
.
DisputeGameFinalityDelaySeconds
+
1
,
"mipsVersion"
:
standard
.
MIPSVersion
+
1
,
"disputeGameType"
:
standard
.
DisputeGameType
,
// This must be set to the permissioned game
"disputeAbsolutePrestate"
:
common
.
Hash
{
'A'
,
'B'
,
'S'
,
'O'
,
'L'
,
'U'
,
'T'
,
'E'
},
"disputeMaxGameDepth"
:
standard
.
DisputeMaxGameDepth
+
1
,
"disputeSplitDepth"
:
standard
.
DisputeSplitDepth
+
1
,
"disputeClockExtension"
:
standard
.
DisputeClockExtension
+
1
,
"disputeMaxClockDuration"
:
standard
.
DisputeMaxClockDuration
+
1
,
"dangerouslyAllowCustomDisputeParameters"
:
true
,
}
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
allocs
:=
st
.
L1StateDump
.
Data
.
Accounts
chainState
:=
st
.
Chains
[
0
]
uint64Caster
:=
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
{
return
common
.
BigToHash
(
new
(
big
.
Int
)
.
SetUint64
(
val
.
(
uint64
)))
}
tests
:=
[]
struct
{
tests
:=
[]
struct
{
name
string
name
string
caster
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
overrides
map
[
string
]
any
address
common
.
Address
}{
}{
{
{
"withdrawalDelaySeconds"
,
name
:
"L2 proxy admin owner not set"
,
uint64Caster
,
overrides
:
map
[
string
]
any
{
st
.
ImplementationsDeployment
.
DelayedWETHImplAddress
,
"proxyAdminOwner"
:
nil
,
},
},
{
"minProposalSizeBytes"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
,
},
{
"challengePeriodSeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
,
},
{
"proofMaturityDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
,
},
{
"disputeGameFinalityDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
,
},
},
{
{
"disputeAbsolutePrestate
"
,
name
:
"base fee vault recipient not set
"
,
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
{
overrides
:
map
[
string
]
any
{
return
val
.
(
common
.
Hash
)
"baseFeeVaultRecipient"
:
nil
,
},
},
chainState
.
PermissionedDisputeGameAddress
,
},
},
{
{
"disputeMaxGameDepth"
,
name
:
"l1 fee vault recipient not set"
,
uint64Caster
,
overrides
:
map
[
string
]
any
{
chainState
.
PermissionedDisputeGameAddress
,
"l1FeeVaultRecipient"
:
nil
,
},
},
},
{
{
"disputeSplitDepth"
,
name
:
"sequencer fee vault recipient not set"
,
uint64Caster
,
overrides
:
map
[
string
]
any
{
chainState
.
PermissionedDisputeGameAddress
,
"sequencerFeeVaultRecipient"
:
nil
,
},
},
},
{
{
"disputeClockExtension"
,
name
:
"l1 chain ID not set"
,
uint64Caster
,
overrides
:
map
[
string
]
any
{
chainState
.
PermissionedDisputeGameAddress
,
"l1ChainID"
:
nil
,
},
},
},
{
{
"disputeMaxClockDuration"
,
name
:
"l2 chain ID not set"
,
uint64Caster
,
overrides
:
map
[
string
]
any
{
chainState
.
PermissionedDisputeGameAddress
,
"l2ChainID"
:
nil
,
},
},
},
}
}
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
checkImmutable
(
t
,
allocs
,
tt
.
address
,
tt
.
caster
(
t
,
intent
.
GlobalDeployOverrides
[
tt
.
name
]))
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
nil
,
broadcaster
.
NoopBroadcaster
(),
deployerAddr
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID1
,
loc
,
loc
)
intent
.
Chains
=
append
(
intent
.
Chains
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID1
))
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
intent
.
GlobalDeployOverrides
=
tt
.
overrides
err
:=
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
)
require
.
Error
(
t
,
err
)
require
.
ErrorContains
(
t
,
err
,
"failed to combine L2 init config"
)
})
})
}
}
}
}
func
TestInteropDeployment
(
t
*
testing
.
T
)
{
func
setupGenesisChain
(
t
*
testing
.
T
)
(
*
pipeline
.
Env
,
pipeline
.
ArtifactsBundle
,
*
state
.
Intent
,
*
state
.
State
)
{
op_e2e
.
InitParallel
(
t
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
...
@@ -763,104 +509,278 @@ func TestInteropDeployment(t *testing.T) {
...
@@ -763,104 +509,278 @@ func TestInteropDeployment(t *testing.T) {
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID1
,
loc
,
loc
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID1
,
loc
,
loc
)
intent
.
Chains
=
append
(
intent
.
Chains
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID1
))
intent
.
Chains
=
append
(
intent
.
Chains
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID1
))
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
intent
.
UseInterop
=
true
return
env
,
bundle
,
intent
,
st
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
chainState
:=
st
.
Chains
[
0
]
depManagerSlot
:=
common
.
HexToHash
(
"0x1708e077affb93e89be2665fb0fb72581be66f84dc00d25fed755ae911905b1c"
)
checkImmutable
(
t
,
st
.
L1StateDump
.
Data
.
Accounts
,
st
.
ImplementationsDeployment
.
SystemConfigImplAddress
,
depManagerSlot
)
proxyAdminOwnerHash
:=
common
.
BytesToHash
(
intent
.
Chains
[
0
]
.
Roles
.
L1ProxyAdminOwner
.
Bytes
())
checkStorageSlot
(
t
,
st
.
L1StateDump
.
Data
.
Accounts
,
chainState
.
SystemConfigProxyAddress
,
depManagerSlot
,
proxyAdminOwnerHash
)
}
}
func
TestInvalidL2Genesis
(
t
*
testing
.
T
)
{
func
localArtifactsLocator
(
t
*
testing
.
T
)
*
opcm
.
ArtifactsLocator
{
op_e2e
.
InitParallel
(
t
)
_
,
testFilename
,
_
,
ok
:=
runtime
.
Caller
(
0
)
require
.
Truef
(
t
,
ok
,
"failed to get test filename"
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
monorepoDir
:=
path
.
Join
(
path
.
Dir
(
testFilename
),
".."
,
".."
,
".."
,
".."
)
artifactsDir
:=
path
.
Join
(
monorepoDir
,
"packages"
,
"contracts-bedrock"
,
"forge-artifacts"
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
artifactsURL
,
err
:=
url
.
Parse
(
fmt
.
Sprintf
(
"file://%s"
,
artifactsDir
))
defer
cancel
()
depKey
:=
new
(
deployerKey
)
l1ChainID
:=
big
.
NewInt
(
77799777
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
loc
:=
&
opcm
.
ArtifactsLocator
{
l2ChainID1
:=
uint256
.
NewInt
(
1
)
URL
:
artifactsURL
,
}
deployerAddr
,
err
:=
dk
.
Address
(
depKey
)
return
loc
}
func
createEnv
(
t
*
testing
.
T
,
ctx
context
.
Context
,
lgr
log
.
Logger
,
l1Client
*
ethclient
.
Client
,
bcaster
broadcaster
.
Broadcaster
,
deployerAddr
common
.
Address
,
)
(
*
pipeline
.
Env
,
pipeline
.
ArtifactsBundle
,
*
script
.
Host
)
{
_
,
testFilename
,
_
,
ok
:=
runtime
.
Caller
(
0
)
require
.
Truef
(
t
,
ok
,
"failed to get test filename"
)
monorepoDir
:=
path
.
Join
(
path
.
Dir
(
testFilename
),
".."
,
".."
,
".."
,
".."
)
artifactsDir
:=
path
.
Join
(
monorepoDir
,
"packages"
,
"contracts-bedrock"
,
"forge-artifacts"
)
artifactsURL
,
err
:=
url
.
Parse
(
fmt
.
Sprintf
(
"file://%s"
,
artifactsDir
))
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
artifactsLocator
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
}
loc
:=
localArtifactsLocator
(
t
)
artifactsFS
,
cleanupArtifacts
,
err
:=
pipeline
.
DownloadArtifacts
(
ctx
,
artifactsLocator
,
pipeline
.
NoopDownloadProgressor
)
require
.
NoError
(
t
,
err
)
defer
func
()
{
require
.
NoError
(
t
,
cleanupArtifacts
())
}()
// these tests were generated by grepping all usages of the deploy
host
,
err
:=
pipeline
.
DefaultScriptHost
(
// config in L2Genesis.s.sol.
bcaster
,
tests
:=
[]
struct
{
lgr
,
name
string
deployerAddr
,
overrides
map
[
string
]
any
artifactsFS
,
}{
0
,
{
)
name
:
"L2 proxy admin owner not set"
,
require
.
NoError
(
t
,
err
)
overrides
:
map
[
string
]
any
{
"proxyAdminOwner"
:
nil
,
env
:=
&
pipeline
.
Env
{
},
StateWriter
:
pipeline
.
NoopStateWriter
(),
},
L1ScriptHost
:
host
,
{
L1Client
:
l1Client
,
name
:
"base fee vault recipient not set"
,
Broadcaster
:
bcaster
,
overrides
:
map
[
string
]
any
{
Deployer
:
deployerAddr
,
"baseFeeVaultRecipient"
:
nil
,
Logger
:
lgr
,
},
}
},
{
bundle
:=
pipeline
.
ArtifactsBundle
{
name
:
"l1 fee vault recipient not set"
,
L1
:
artifactsFS
,
overrides
:
map
[
string
]
any
{
L2
:
artifactsFS
,
"l1FeeVaultRecipient"
:
nil
,
}
},
},
return
env
,
bundle
,
host
{
}
name
:
"sequencer fee vault recipient not set"
,
overrides
:
map
[
string
]
any
{
func
addrFor
(
t
*
testing
.
T
,
dk
*
devkeys
.
MnemonicDevKeys
,
key
devkeys
.
Key
)
common
.
Address
{
"sequencerFeeVaultRecipient"
:
nil
,
addr
,
err
:=
dk
.
Address
(
key
)
},
require
.
NoError
(
t
,
err
)
return
addr
}
func
newIntent
(
t
*
testing
.
T
,
l1ChainID
*
big
.
Int
,
dk
*
devkeys
.
MnemonicDevKeys
,
l2ChainID
*
uint256
.
Int
,
l1Loc
*
opcm
.
ArtifactsLocator
,
l2Loc
*
opcm
.
ArtifactsLocator
,
)
(
*
state
.
Intent
,
*
state
.
State
)
{
intent
:=
&
state
.
Intent
{
DeploymentStrategy
:
state
.
DeploymentStrategyLive
,
L1ChainID
:
l1ChainID
.
Uint64
(),
SuperchainRoles
:
&
state
.
SuperchainRoles
{
ProxyAdminOwner
:
addrFor
(
t
,
dk
,
devkeys
.
L1ProxyAdminOwnerRole
.
Key
(
l1ChainID
)),
ProtocolVersionsOwner
:
addrFor
(
t
,
dk
,
devkeys
.
SuperchainDeployerKey
.
Key
(
l1ChainID
)),
Guardian
:
addrFor
(
t
,
dk
,
devkeys
.
SuperchainConfigGuardianKey
.
Key
(
l1ChainID
)),
},
},
{
FundDevAccounts
:
true
,
name
:
"l1 chain ID not set"
,
L1ContractsLocator
:
l1Loc
,
overrides
:
map
[
string
]
any
{
L2ContractsLocator
:
l2Loc
,
"l1ChainID"
:
nil
,
Chains
:
[]
*
state
.
ChainIntent
{
}
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID
)
,
},
},
{
}
name
:
"l2 chain ID not set"
,
st
:=
&
state
.
State
{
overrides
:
map
[
string
]
any
{
Version
:
1
,
"l2ChainID"
:
nil
,
}
},
return
intent
,
st
}
func
newChainIntent
(
t
*
testing
.
T
,
dk
*
devkeys
.
MnemonicDevKeys
,
l1ChainID
*
big
.
Int
,
l2ChainID
*
uint256
.
Int
)
*
state
.
ChainIntent
{
return
&
state
.
ChainIntent
{
ID
:
l2ChainID
.
Bytes32
(),
BaseFeeVaultRecipient
:
addrFor
(
t
,
dk
,
devkeys
.
BaseFeeVaultRecipientRole
.
Key
(
l1ChainID
)),
L1FeeVaultRecipient
:
addrFor
(
t
,
dk
,
devkeys
.
L1FeeVaultRecipientRole
.
Key
(
l1ChainID
)),
SequencerFeeVaultRecipient
:
addrFor
(
t
,
dk
,
devkeys
.
SequencerFeeVaultRecipientRole
.
Key
(
l1ChainID
)),
Eip1559Denominator
:
50
,
Eip1559Elasticity
:
6
,
Roles
:
state
.
ChainRoles
{
L1ProxyAdminOwner
:
addrFor
(
t
,
dk
,
devkeys
.
L2ProxyAdminOwnerRole
.
Key
(
l1ChainID
)),
L2ProxyAdminOwner
:
addrFor
(
t
,
dk
,
devkeys
.
L2ProxyAdminOwnerRole
.
Key
(
l1ChainID
)),
SystemConfigOwner
:
addrFor
(
t
,
dk
,
devkeys
.
SystemConfigOwner
.
Key
(
l1ChainID
)),
UnsafeBlockSigner
:
addrFor
(
t
,
dk
,
devkeys
.
SequencerP2PRole
.
Key
(
l1ChainID
)),
Batcher
:
addrFor
(
t
,
dk
,
devkeys
.
BatcherRole
.
Key
(
l1ChainID
)),
Proposer
:
addrFor
(
t
,
dk
,
devkeys
.
ProposerRole
.
Key
(
l1ChainID
)),
Challenger
:
addrFor
(
t
,
dk
,
devkeys
.
ChallengerRole
.
Key
(
l1ChainID
)),
},
},
}
}
for
_
,
tt
:=
range
tests
{
}
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
nil
,
broadcaster
.
NoopBroadcaster
(),
deployerAddr
)
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID1
,
loc
,
loc
)
intent
.
Chains
=
append
(
intent
.
Chains
,
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID1
))
intent
.
DeploymentStrategy
=
state
.
DeploymentStrategyGenesis
intent
.
GlobalDeployOverrides
=
tt
.
overrides
err
:=
deployer
.
ApplyPipeline
(
type
codeGetter
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
ctx
,
env
,
func
ethClientCodeGetter
(
ctx
context
.
Context
,
client
*
ethclient
.
Client
)
codeGetter
{
bundle
,
return
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
{
intent
,
code
,
err
:=
client
.
CodeAt
(
ctx
,
addr
,
nil
)
st
,
require
.
NoError
(
t
,
err
)
)
return
code
require
.
Error
(
t
,
err
)
}
require
.
ErrorContains
(
t
,
err
,
"failed to combine L2 init config"
)
}
func
stateDumpCodeGetter
(
st
*
state
.
State
)
codeGetter
{
return
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
{
acc
,
ok
:=
st
.
L1StateDump
.
Data
.
Accounts
[
addr
]
require
.
True
(
t
,
ok
,
"no account found for address %s"
,
addr
)
return
acc
.
Code
}
}
func
validateSuperchainDeployment
(
t
*
testing
.
T
,
st
*
state
.
State
,
cg
codeGetter
)
{
addrs
:=
[]
struct
{
name
string
addr
common
.
Address
}{
{
"SuperchainProxyAdmin"
,
st
.
SuperchainDeployment
.
ProxyAdminAddress
},
{
"SuperchainConfigProxy"
,
st
.
SuperchainDeployment
.
SuperchainConfigProxyAddress
},
{
"SuperchainConfigImpl"
,
st
.
SuperchainDeployment
.
SuperchainConfigImplAddress
},
{
"ProtocolVersionsProxy"
,
st
.
SuperchainDeployment
.
ProtocolVersionsProxyAddress
},
{
"ProtocolVersionsImpl"
,
st
.
SuperchainDeployment
.
ProtocolVersionsImplAddress
},
{
"OpcmProxy"
,
st
.
ImplementationsDeployment
.
OpcmProxyAddress
},
{
"PreimageOracleSingleton"
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
},
{
"MipsSingleton"
,
st
.
ImplementationsDeployment
.
MipsSingletonAddress
},
}
for
_
,
addr
:=
range
addrs
{
t
.
Run
(
addr
.
name
,
func
(
t
*
testing
.
T
)
{
code
:=
cg
(
t
,
addr
.
addr
)
require
.
NotEmpty
(
t
,
code
,
"contract %s at %s has no code"
,
addr
.
name
,
addr
.
addr
)
})
})
}
}
}
}
func
validateOPChainDeployment
(
t
*
testing
.
T
,
cg
codeGetter
,
st
*
state
.
State
,
intent
*
state
.
Intent
)
{
// Validate that the implementation addresses are always set, even in subsequent deployments
// that pull from an existing OPCM deployment.
implAddrs
:=
[]
struct
{
name
string
addr
common
.
Address
}{
{
"DelayedWETHImplAddress"
,
st
.
ImplementationsDeployment
.
DelayedWETHImplAddress
},
{
"OptimismPortalImplAddress"
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
},
{
"SystemConfigImplAddress"
,
st
.
ImplementationsDeployment
.
SystemConfigImplAddress
},
{
"L1CrossDomainMessengerImplAddress"
,
st
.
ImplementationsDeployment
.
L1CrossDomainMessengerImplAddress
},
{
"L1ERC721BridgeImplAddress"
,
st
.
ImplementationsDeployment
.
L1ERC721BridgeImplAddress
},
{
"L1StandardBridgeImplAddress"
,
st
.
ImplementationsDeployment
.
L1StandardBridgeImplAddress
},
{
"OptimismMintableERC20FactoryImplAddress"
,
st
.
ImplementationsDeployment
.
OptimismMintableERC20FactoryImplAddress
},
{
"DisputeGameFactoryImplAddress"
,
st
.
ImplementationsDeployment
.
DisputeGameFactoryImplAddress
},
{
"MipsSingletonAddress"
,
st
.
ImplementationsDeployment
.
MipsSingletonAddress
},
{
"PreimageOracleSingletonAddress"
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
},
}
for
_
,
addr
:=
range
implAddrs
{
require
.
NotEmpty
(
t
,
addr
.
addr
,
"%s should be set"
,
addr
.
name
)
code
:=
cg
(
t
,
addr
.
addr
)
require
.
NotEmpty
(
t
,
code
,
"contract %s at %s has no code"
,
addr
.
name
,
addr
.
addr
)
}
for
i
,
chainState
:=
range
st
.
Chains
{
chainAddrs
:=
[]
struct
{
name
string
addr
common
.
Address
}{
{
"ProxyAdminAddress"
,
chainState
.
ProxyAdminAddress
},
{
"AddressManagerAddress"
,
chainState
.
AddressManagerAddress
},
{
"L1ERC721BridgeProxyAddress"
,
chainState
.
L1ERC721BridgeProxyAddress
},
{
"SystemConfigProxyAddress"
,
chainState
.
SystemConfigProxyAddress
},
{
"OptimismMintableERC20FactoryProxyAddress"
,
chainState
.
OptimismMintableERC20FactoryProxyAddress
},
{
"L1StandardBridgeProxyAddress"
,
chainState
.
L1StandardBridgeProxyAddress
},
{
"L1CrossDomainMessengerProxyAddress"
,
chainState
.
L1CrossDomainMessengerProxyAddress
},
{
"OptimismPortalProxyAddress"
,
chainState
.
OptimismPortalProxyAddress
},
{
"DisputeGameFactoryProxyAddress"
,
chainState
.
DisputeGameFactoryProxyAddress
},
{
"AnchorStateRegistryProxyAddress"
,
chainState
.
AnchorStateRegistryProxyAddress
},
{
"FaultDisputeGameAddress"
,
chainState
.
FaultDisputeGameAddress
},
{
"PermissionedDisputeGameAddress"
,
chainState
.
PermissionedDisputeGameAddress
},
{
"DelayedWETHPermissionedGameProxyAddress"
,
chainState
.
DelayedWETHPermissionedGameProxyAddress
},
// {"DelayedWETHPermissionlessGameProxyAddress", chainState.DelayedWETHPermissionlessGameProxyAddress},
}
for
_
,
addr
:=
range
chainAddrs
{
// TODO Delete this `if`` block once FaultDisputeGameAddress is deployed.
if
addr
.
name
==
"FaultDisputeGameAddress"
{
continue
}
code
:=
cg
(
t
,
addr
.
addr
)
require
.
NotEmpty
(
t
,
code
,
"contract %s at %s for chain %s has no code"
,
addr
.
name
,
addr
.
addr
,
chainState
.
ID
)
}
alloc
:=
chainState
.
Allocs
.
Data
.
Accounts
chainIntent
:=
intent
.
Chains
[
i
]
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
BaseFeeVaultAddr
,
chainIntent
.
BaseFeeVaultRecipient
)
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
L1FeeVaultAddr
,
chainIntent
.
L1FeeVaultRecipient
)
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
SequencerFeeVaultAddr
,
chainIntent
.
SequencerFeeVaultRecipient
)
checkImmutableBehindProxy
(
t
,
alloc
,
predeploys
.
OptimismMintableERC721FactoryAddr
,
common
.
BigToHash
(
new
(
big
.
Int
)
.
SetUint64
(
intent
.
L1ChainID
)))
// ownership slots
var
addrAsSlot
common
.
Hash
addrAsSlot
.
SetBytes
(
chainIntent
.
Roles
.
L1ProxyAdminOwner
.
Bytes
())
// slot 0
ownerSlot
:=
common
.
Hash
{}
checkStorageSlot
(
t
,
alloc
,
predeploys
.
ProxyAdminAddr
,
ownerSlot
,
addrAsSlot
)
var
defaultGovOwner
common
.
Hash
defaultGovOwner
.
SetBytes
(
common
.
HexToAddress
(
"0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAdDEad"
)
.
Bytes
())
checkStorageSlot
(
t
,
alloc
,
predeploys
.
GovernanceTokenAddr
,
common
.
Hash
{
31
:
0x0a
},
defaultGovOwner
)
require
.
Equal
(
t
,
int
(
chainIntent
.
Eip1559Denominator
),
50
,
"EIP1559Denominator should be set"
)
require
.
Equal
(
t
,
int
(
chainIntent
.
Eip1559Elasticity
),
6
,
"EIP1559Elasticity should be set"
)
}
}
func
getEIP1967ImplementationAddress
(
t
*
testing
.
T
,
allocations
types
.
GenesisAlloc
,
proxyAddress
common
.
Address
)
common
.
Address
{
storage
:=
allocations
[
proxyAddress
]
.
Storage
storageValue
:=
storage
[
genesis
.
ImplementationSlot
]
require
.
NotEmpty
(
t
,
storageValue
,
"Implementation address for %s should be set"
,
proxyAddress
)
return
common
.
HexToAddress
(
storageValue
.
Hex
())
}
type
bytesMarshaler
interface
{
Bytes
()
[]
byte
}
func
checkImmutableBehindProxy
(
t
*
testing
.
T
,
allocations
types
.
GenesisAlloc
,
proxyContract
common
.
Address
,
thing
bytesMarshaler
)
{
implementationAddress
:=
getEIP1967ImplementationAddress
(
t
,
allocations
,
proxyContract
)
checkImmutable
(
t
,
allocations
,
implementationAddress
,
thing
)
}
func
checkImmutable
(
t
*
testing
.
T
,
allocations
types
.
GenesisAlloc
,
implementationAddress
common
.
Address
,
thing
bytesMarshaler
)
{
account
,
ok
:=
allocations
[
implementationAddress
]
require
.
True
(
t
,
ok
,
"%s not found in allocations"
,
implementationAddress
)
require
.
NotEmpty
(
t
,
account
.
Code
,
"%s should have code"
,
implementationAddress
)
require
.
True
(
t
,
bytes
.
Contains
(
account
.
Code
,
thing
.
Bytes
()),
"%s code should contain %s immutable"
,
implementationAddress
,
hex
.
EncodeToString
(
thing
.
Bytes
()),
)
}
func
checkStorageSlot
(
t
*
testing
.
T
,
allocs
types
.
GenesisAlloc
,
address
common
.
Address
,
slot
common
.
Hash
,
expected
common
.
Hash
)
{
account
,
ok
:=
allocs
[
address
]
require
.
True
(
t
,
ok
,
"account not found for address %s"
,
address
)
value
,
ok
:=
account
.
Storage
[
slot
]
if
expected
==
(
common
.
Hash
{})
{
require
.
False
(
t
,
ok
,
"slot %s for account %s should not be set"
,
slot
,
address
)
return
}
require
.
True
(
t
,
ok
,
"slot %s not found for account %s"
,
slot
,
address
)
require
.
Equal
(
t
,
expected
,
value
,
"slot %s for account %s should be %s"
,
slot
,
address
,
expected
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment