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
Show 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 (
"testing"
"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-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/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
...
...
@@ -156,336 +155,238 @@ func TestEndToEndApply(t *testing.T) {
})
}
func
localArtifactsLocator
(
t
*
testing
.
T
)
*
opcm
.
ArtifactsLocator
{
_
,
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
)
loc
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
}
return
loc
}
func
TestApplyExistingOPCM
(
t
*
testing
.
T
)
{
anvil
.
Test
(
t
)
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
)
artifactsLocator
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
forkRPCUrl
:=
os
.
Getenv
(
"SEPOLIA_RPC_URL"
)
if
forkRPCUrl
==
""
{
t
.
Skip
(
"no fork RPC URL provided"
)
}
artifactsFS
,
cleanupArtifacts
,
err
:=
pipeline
.
DownloadArtifacts
(
ctx
,
artifactsLocator
,
pipeline
.
NoopDownloadProgressor
)
require
.
NoError
(
t
,
err
)
defer
func
()
{
require
.
NoError
(
t
,
cleanupArtifacts
())
}()
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
host
,
err
:=
pipeline
.
DefaultScriptHost
(
bcaster
,
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Minute
)
defer
cancel
()
runner
,
err
:=
anvil
.
New
(
forkRPCUrl
,
lgr
,
deployerAddr
,
artifactsFS
,
0
,
)
require
.
NoError
(
t
,
err
)
env
:=
&
pipeline
.
Env
{
StateWriter
:
pipeline
.
NoopStateWriter
(),
L1ScriptHost
:
host
,
L1Client
:
l1Client
,
Broadcaster
:
bcaster
,
Deployer
:
deployerAddr
,
Logger
:
lgr
,
}
require
.
NoError
(
t
,
runner
.
Start
(
ctx
))
t
.
Cleanup
(
func
()
{
require
.
NoError
(
t
,
runner
.
Stop
())
})
bundle
:=
pipeline
.
ArtifactsBundle
{
L1
:
artifactsFS
,
L2
:
artifactsFS
,
}
l1Client
,
err
:=
ethclient
.
Dial
(
runner
.
RPCUrl
())
require
.
NoError
(
t
,
err
)
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
{
addr
,
err
:=
dk
.
Address
(
key
)
l2ChainID
:=
uint256
.
NewInt
(
1
)
bcaster
,
err
:=
broadcaster
.
NewKeyedBroadcaster
(
broadcaster
.
KeyedBroadcasterOpts
{
Logger
:
lgr
,
ChainID
:
l1ChainID
,
Client
:
l1Client
,
Signer
:
signer
,
From
:
deployerAddr
,
})
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
,
L1ContractsLocator
:
l1Loc
,
L2ContractsLocator
:
l2Loc
,
Chains
:
[]
*
state
.
ChainIntent
{
newChainIntent
(
t
,
dk
,
l1ChainID
,
l2ChainID
),
},
}
st
:=
&
state
.
State
{
Version
:
1
,
}
return
intent
,
st
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
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
validateOPChainDeployment
(
t
,
ethClientCodeGetter
(
ctx
,
l1Client
),
st
,
intent
)
}
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
)),
},
func
TestL2BlockTimeOverride
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
kurtosisutil
.
Test
(
t
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
intent
.
GlobalDeployOverrides
=
map
[
string
]
interface
{}{
"l2BlockTime"
:
float64
(
3
),
}
}
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
{
return
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
{
code
,
err
:=
client
.
CodeAt
(
ctx
,
addr
,
nil
)
cfg
,
err
:=
state
.
CombineDeployConfig
(
intent
,
intent
.
Chains
[
0
],
st
,
st
.
Chains
[
0
])
require
.
NoError
(
t
,
err
)
return
code
}
require
.
Equal
(
t
,
uint64
(
3
),
cfg
.
L2InitializationConfig
.
L2CoreDeployConfig
.
L2BlockTime
,
"L2 block time should be 3 seconds"
)
}
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
TestApplyGenesisStrategy
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
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
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
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
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
)
}
func
TestProofParamOverrides
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
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
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
require
.
Equal
(
t
,
int
(
chainIntent
.
Eip1559Denominator
),
50
,
"EIP1559Denominator should be set"
)
require
.
Equal
(
t
,
int
(
chainIntent
.
Eip1559Elasticity
),
6
,
"EIP1559Elasticity should be set"
)
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
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
)
{
implementationAddress
:=
getEIP1967ImplementationAddress
(
t
,
allocations
,
proxyContract
)
checkImmutable
(
t
,
allocations
,
implementationAddress
,
thing
)
}
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
))
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
()),
)
}
allocs
:=
st
.
L1StateDump
.
Data
.
Accounts
chainState
:=
st
.
Chains
[
0
]
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
uint64Caster
:=
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
{
return
common
.
BigToHash
(
new
(
big
.
Int
)
.
SetUint64
(
val
.
(
uint64
)))
}
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"
)
if
forkRPCUrl
==
""
{
t
.
Skip
(
"no fork RPC URL provided"
)
tests
:=
[]
struct
{
name
string
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
,
},
}
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Minute
)
defer
cancel
()
runner
,
err
:=
anvil
.
New
(
forkRPCUrl
,
lgr
,
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
runner
.
Start
(
ctx
))
t
.
Cleanup
(
func
()
{
require
.
NoError
(
t
,
runner
.
Stop
())
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
checkImmutable
(
t
,
allocs
,
tt
.
address
,
tt
.
caster
(
t
,
intent
.
GlobalDeployOverrides
[
tt
.
name
]))
})
}
}
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
)
func
TestInteropDeployment
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
env
,
bundle
,
_
:=
createEnv
(
t
,
ctx
,
lgr
,
l1Client
,
bcaster
,
deployerAddr
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
defer
cancel
()
intent
,
st
:=
newIntent
(
t
,
l1ChainID
,
dk
,
l2ChainID
,
opcm
.
DefaultL1ContractsLocator
,
opcm
.
DefaultL2ContractsLocator
,
)
env
,
bundle
,
intent
,
st
:=
setupGenesisChain
(
t
)
intent
.
UseInterop
=
true
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
ctx
,
...
...
@@ -495,295 +396,98 @@ func TestApplyExistingOPCM(t *testing.T) {
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
)
kurtosisutil
.
Test
(
t
)
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
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
)
l1ChainID
:=
big
.
NewInt
(
77799777
)
dk
,
err
:=
devkeys
.
NewMnemonicDevKeys
(
devkeys
.
TestMnemonic
)
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
)
require
.
NoError
(
t
,
err
)
loc
:=
localArtifactsLocator
(
t
)
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
,
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
)))
}
// these tests were generated by grepping all usages of the deploy
// config in L2Genesis.s.sol.
tests
:=
[]
struct
{
name
string
caster
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
address
common
.
Address
overrides
map
[
string
]
any
}{
{
"withdrawalDelaySeconds
"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
DelayedWETHImplAddress
,
name
:
"L2 proxy admin owner not set
"
,
overrides
:
map
[
string
]
any
{
"proxyAdminOwner"
:
nil
,
},
{
"minProposalSizeBytes"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
,
},
{
"challengePeriodSeconds
"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
PreimageOracleSingletonAddress
,
name
:
"base fee vault recipient not set
"
,
overrides
:
map
[
string
]
any
{
"baseFeeVaultRecipient"
:
nil
,
},
{
"proofMaturityDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
,
},
{
"disputeGameFinalityDelaySeconds"
,
uint64Caster
,
st
.
ImplementationsDeployment
.
OptimismPortalImplAddress
,
name
:
"l1 fee vault recipient not set"
,
overrides
:
map
[
string
]
any
{
"l1FeeVaultRecipient"
:
nil
,
},
},
{
"disputeAbsolutePrestate
"
,
func
(
t
*
testing
.
T
,
val
any
)
common
.
Hash
{
return
val
.
(
common
.
Hash
)
name
:
"sequencer fee vault recipient not set
"
,
overrides
:
map
[
string
]
any
{
"sequencerFeeVaultRecipient"
:
nil
,
},
chainState
.
PermissionedDisputeGameAddress
,
},
{
"disputeMaxGameDepth
"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
name
:
"l1 chain ID not set
"
,
overrides
:
map
[
string
]
any
{
"l1ChainID"
:
nil
,
},
{
"disputeSplitDepth"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
},
{
"disputeClockExtension
"
,
uint64Caster
,
chainState
.
PermissionedDisputeGameAddress
,
name
:
"l2 chain ID not set
"
,
overrides
:
map
[
string
]
any
{
"l2ChainID"
:
nil
,
},
{
"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
]))
})
}
}
func
TestInteropDeployment
(
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
.
UseInterop
=
true
intent
.
GlobalDeployOverrides
=
tt
.
overrides
require
.
NoError
(
t
,
deployer
.
ApplyPipeline
(
err
:=
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
)
)
require
.
Error
(
t
,
err
)
require
.
ErrorContains
(
t
,
err
,
"failed to combine L2 init config"
)
})
}
}
func
TestInvalidL2Genesis
(
t
*
testing
.
T
)
{
op_e2e
.
InitParallel
(
t
)
func
setupGenesisChain
(
t
*
testing
.
T
)
(
*
pipeline
.
Env
,
pipeline
.
ArtifactsBundle
,
*
state
.
Intent
,
*
state
.
State
)
{
lgr
:=
testlog
.
Logger
(
t
,
slog
.
LevelDebug
)
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
...
...
@@ -801,66 +505,282 @@ func TestInvalidL2Genesis(t *testing.T) {
loc
:=
localArtifactsLocator
(
t
)
// these tests were generated by grepping all usages of the deploy
// config in L2Genesis.s.sol.
tests
:=
[]
struct
{
name
string
overrides
map
[
string
]
any
}{
{
name
:
"L2 proxy admin owner not set"
,
overrides
:
map
[
string
]
any
{
"proxyAdminOwner"
:
nil
,
},
},
{
name
:
"base fee vault recipient not set"
,
overrides
:
map
[
string
]
any
{
"baseFeeVaultRecipient"
:
nil
,
},
},
{
name
:
"l1 fee vault recipient not set"
,
overrides
:
map
[
string
]
any
{
"l1FeeVaultRecipient"
:
nil
,
},
},
{
name
:
"sequencer fee vault recipient not set"
,
overrides
:
map
[
string
]
any
{
"sequencerFeeVaultRecipient"
:
nil
,
},
},
{
name
:
"l1 chain ID not set"
,
overrides
:
map
[
string
]
any
{
"l1ChainID"
:
nil
,
},
},
{
name
:
"l2 chain ID not set"
,
overrides
:
map
[
string
]
any
{
"l2ChainID"
:
nil
,
},
},
}
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
return
env
,
bundle
,
intent
,
st
}
err
:=
deployer
.
ApplyPipeline
(
ctx
,
env
,
bundle
,
intent
,
st
,
func
localArtifactsLocator
(
t
*
testing
.
T
)
*
opcm
.
ArtifactsLocator
{
_
,
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
)
loc
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
}
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
)
artifactsLocator
:=
&
opcm
.
ArtifactsLocator
{
URL
:
artifactsURL
,
}
artifactsFS
,
cleanupArtifacts
,
err
:=
pipeline
.
DownloadArtifacts
(
ctx
,
artifactsLocator
,
pipeline
.
NoopDownloadProgressor
)
require
.
NoError
(
t
,
err
)
defer
func
()
{
require
.
NoError
(
t
,
cleanupArtifacts
())
}()
host
,
err
:=
pipeline
.
DefaultScriptHost
(
bcaster
,
lgr
,
deployerAddr
,
artifactsFS
,
0
,
)
require
.
Error
(
t
,
err
)
require
.
ErrorContains
(
t
,
err
,
"failed to combine L2 init config"
)
require
.
NoError
(
t
,
err
)
env
:=
&
pipeline
.
Env
{
StateWriter
:
pipeline
.
NoopStateWriter
(),
L1ScriptHost
:
host
,
L1Client
:
l1Client
,
Broadcaster
:
bcaster
,
Deployer
:
deployerAddr
,
Logger
:
lgr
,
}
bundle
:=
pipeline
.
ArtifactsBundle
{
L1
:
artifactsFS
,
L2
:
artifactsFS
,
}
return
env
,
bundle
,
host
}
func
addrFor
(
t
*
testing
.
T
,
dk
*
devkeys
.
MnemonicDevKeys
,
key
devkeys
.
Key
)
common
.
Address
{
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
,
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
{
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
)),
},
}
}
type
codeGetter
func
(
t
*
testing
.
T
,
addr
common
.
Address
)
[]
byte
func
ethClientCodeGetter
(
ctx
context
.
Context
,
client
*
ethclient
.
Client
)
codeGetter
{
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
{
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