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
966e1b19
Unverified
Commit
966e1b19
authored
2 years ago
by
Mark Tyneway
Committed by
GitHub
2 years ago
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3119 from ethereum-optimism/ctb/genesis-l2-immutables
contracts-bedrock: in place handling of immutables
parents
64337ed5
1124f30c
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
255 additions
and
18 deletions
+255
-18
cool-items-smell.md
.changeset/cool-items-smell.md
+5
-0
config.yml
.circleci/config.yml
+5
-3
hardhat.config.ts
packages/contracts-bedrock/hardhat.config.ts
+1
-0
check-l2-config.ts
packages/contracts-bedrock/tasks/check-l2-config.ts
+31
-0
genesis-l2.ts
packages/contracts-bedrock/tasks/genesis-l2.ts
+213
-15
No files found.
.changeset/cool-items-smell.md
0 → 100644
View file @
966e1b19
---
'
@eth-optimism/contracts-bedrock'
:
patch
---
Update genesis-l2 task to set immutables in the bytecode
This diff is collapsed.
Click to expand it.
.circleci/config.yml
View file @
966e1b19
...
@@ -451,7 +451,6 @@ jobs:
...
@@ -451,7 +451,6 @@ jobs:
name
:
Do a deposit
name
:
Do a deposit
no_output_timeout
:
5m
no_output_timeout
:
5m
command
:
|
command
:
|
npx hardhat compile
npx hardhat deposit \
npx hardhat deposit \
--to 0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244 \
--to 0xB79f76EF2c5F0286176833E7B2eEe103b1CC3244 \
--amount-eth 1 \
--amount-eth 1 \
...
@@ -460,8 +459,11 @@ jobs:
...
@@ -460,8 +459,11 @@ jobs:
working_directory
:
packages/contracts-bedrock
working_directory
:
packages/contracts-bedrock
-
run
:
-
run
:
name
:
Check the status
name
:
Check the status
command
:
|
command
:
npx hardhat check-op-node
npx hardhat check-op-node
working_directory
:
packages/contracts-bedrock
-
run
:
name
:
Check L2 Config
command
:
npx hardhat check-l2-config
working_directory
:
packages/contracts-bedrock
working_directory
:
packages/contracts-bedrock
integration-tests
:
integration-tests
:
...
...
This diff is collapsed.
Click to expand it.
packages/contracts-bedrock/hardhat.config.ts
View file @
966e1b19
...
@@ -15,6 +15,7 @@ import './tasks/deposits'
...
@@ -15,6 +15,7 @@ import './tasks/deposits'
import
'
./tasks/rekey
'
import
'
./tasks/rekey
'
import
'
./tasks/rollup-config
'
import
'
./tasks/rollup-config
'
import
'
./tasks/check-op-node
'
import
'
./tasks/check-op-node
'
import
'
./tasks/check-l2-config
'
subtask
(
TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS
).
setAction
(
subtask
(
TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS
).
setAction
(
async
(
_
,
__
,
runSuper
)
=>
{
async
(
_
,
__
,
runSuper
)
=>
{
...
...
This diff is collapsed.
Click to expand it.
packages/contracts-bedrock/tasks/check-l2-config.ts
0 → 100644
View file @
966e1b19
import
{
task
,
types
}
from
'
hardhat/config
'
import
{
providers
}
from
'
ethers
'
import
'
@nomiclabs/hardhat-ethers
'
import
{
predeploys
,
getContractInterface
}
from
'
../src
'
task
(
'
check-l2-config
'
,
'
Validate L2 config
'
)
.
addParam
(
'
l2ProviderUrl
'
,
'
L2 provider URL.
'
,
'
http://localhost:9545
'
,
types
.
string
)
.
setAction
(
async
(
args
,
hre
)
=>
{
const
{
l2ProviderUrl
}
=
args
const
l2Provider
=
new
providers
.
JsonRpcProvider
(
l2ProviderUrl
)
const
OptimismMintableERC20Factory
=
new
hre
.
ethers
.
Contract
(
predeploys
.
OptimismMintableERC20Factory
,
getContractInterface
(
'
OptimismMintableERC20Factory
'
),
l2Provider
)
const
bridge
=
await
OptimismMintableERC20Factory
.
bridge
()
console
.
log
(
`OptimismMintableERC20Factory.bridge() ->
${
bridge
}
`
)
if
(
bridge
!==
predeploys
.
L2StandardBridge
)
{
throw
new
Error
(
`L2StandardBridge not set correctly. Got
${
bridge
}
, expected
${
predeploys
.
L2StandardBridge
}
`
)
}
})
This diff is collapsed.
Click to expand it.
packages/contracts-bedrock/tasks/genesis-l2.ts
View file @
966e1b19
...
@@ -5,12 +5,19 @@ import assert from 'assert'
...
@@ -5,12 +5,19 @@ import assert from 'assert'
import
{
OptimismGenesis
,
State
}
from
'
@eth-optimism/core-utils
'
import
{
OptimismGenesis
,
State
}
from
'
@eth-optimism/core-utils
'
import
'
hardhat-deploy
'
import
'
hardhat-deploy
'
import
'
@eth-optimism/hardhat-deploy-config
'
import
'
@eth-optimism/hardhat-deploy-config
'
import
{
ethers
}
from
'
ethers
'
import
{
ethers
,
utils
,
BigNumber
}
from
'
ethers
'
import
{
task
}
from
'
hardhat/config
'
import
{
task
}
from
'
hardhat/config
'
import
{
HardhatRuntimeEnvironment
}
from
'
hardhat/types
'
import
{
HardhatRuntimeEnvironment
}
from
'
hardhat/types
'
import
{
CompilerOutputSource
,
CompilerOutputContract
,
BuildInfo
,
}
from
'
hardhat/types/artifacts
'
import
{
predeploys
}
from
'
../src
'
import
{
predeploys
}
from
'
../src
'
const
{
hexZeroPad
,
hexConcat
,
hexDataSlice
,
getAddress
}
=
utils
const
prefix
=
'
0x420000000000000000000000000000000000
'
const
prefix
=
'
0x420000000000000000000000000000000000
'
const
implementationSlot
=
const
implementationSlot
=
'
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
'
'
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc
'
...
@@ -18,11 +25,16 @@ const adminSlot =
...
@@ -18,11 +25,16 @@ const adminSlot =
'
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
'
'
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103
'
const
toCodeAddr
=
(
addr
:
string
)
=>
{
const
toCodeAddr
=
(
addr
:
string
)
=>
{
const
address
=
ethers
.
utils
.
hexConcat
([
const
address
=
hexConcat
([
'
0xc0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3
'
,
'
0xc0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3
'
,
'
0x
'
+
addr
.
slice
(
prefix
.
length
),
'
0x
'
+
addr
.
slice
(
prefix
.
length
),
])
])
return
ethers
.
utils
.
getAddress
(
address
)
return
getAddress
(
address
)
}
const
toBytes32
=
(
num
:
number
):
string
=>
{
const
big
=
BigNumber
.
from
(
num
)
return
hexZeroPad
(
big
.
toHexString
(),
32
)
}
}
const
assertEvenLength
=
(
str
:
string
)
=>
{
const
assertEvenLength
=
(
str
:
string
)
=>
{
...
@@ -46,6 +58,141 @@ const getStorageLayout = async (
...
@@ -46,6 +58,141 @@ const getStorageLayout = async (
throw
new
Error
(
`Cannot locate storageLayout for
${
name
}
`
)
throw
new
Error
(
`Cannot locate storageLayout for
${
name
}
`
)
}
}
// Find the contract and source from the build info
const
findContractAndSource
=
(
name
:
string
,
buildInfo
:
BuildInfo
)
=>
{
const
sources
=
buildInfo
.
output
.
sources
const
contracts
=
buildInfo
.
output
.
contracts
const
compilerOutputContracts
:
CompilerOutputContract
[]
=
[]
for
(
const
[
contractName
,
contract
]
of
Object
.
entries
(
contracts
))
{
if
(
path
.
basename
(
contractName
,
'
.sol
'
)
===
name
)
{
compilerOutputContracts
.
push
(
contract
[
name
])
}
}
if
(
compilerOutputContracts
.
length
===
0
)
{
throw
new
Error
(
`Cannot find compiler output contract for
${
name
}
`
)
}
if
(
compilerOutputContracts
.
length
!==
1
)
{
console
.
log
(
`Unexpected number of contracts for
${
name
}
`
)
}
const
outputContract
=
compilerOutputContracts
[
0
]
const
compilerOutputSources
:
CompilerOutputSource
[]
=
[]
for
(
const
[
contractName
,
source
]
of
Object
.
entries
(
sources
))
{
if
(
path
.
basename
(
contractName
,
'
.sol
'
)
===
name
)
{
compilerOutputSources
.
push
(
source
as
CompilerOutputSource
)
}
}
if
(
compilerOutputSources
.
length
===
0
)
{
throw
new
Error
(
`Cannot find compiler output source for
${
name
}
`
)
}
if
(
compilerOutputSources
.
length
!==
1
)
{
console
.
log
(
`Unexpected number of sources for
${
name
}
`
)
}
const
outputSource
=
compilerOutputSources
[
0
]
return
{
outputContract
,
outputSource
}
}
const
replaceImmutables
=
async
(
hre
:
HardhatRuntimeEnvironment
,
name
:
string
,
immutables
:
object
):
Promise
<
string
>
=>
{
const
artifact
=
await
hre
.
artifacts
.
readArtifact
(
name
)
const
buildInfo
=
await
hre
.
artifacts
.
getBuildInfo
(
name
)
const
{
outputContract
,
outputSource
}
=
findContractAndSource
(
name
,
buildInfo
)
// Get the immutable references. They look like this:
// { ast-id: [ {start, length} ] }
const
immutableReferences
=
outputContract
.
evm
.
deployedBytecode
.
immutableReferences
const
names
=
{}
// Recursively find all of the immutables by traversing the solc output ast
const
findNames
=
(
ast
:
any
)
=>
{
// Add the name of the variable if it is an immutable
const
isImmutable
=
ast
.
mutability
===
'
immutable
'
const
isASTNode
=
typeof
ast
.
name
===
'
string
'
&&
typeof
ast
.
id
===
'
number
'
if
(
isASTNode
&&
isImmutable
)
{
names
[
ast
.
name
]
=
ast
.
id
}
// Iterate over each node
if
(
Array
.
isArray
(
ast
.
nodes
))
{
for
(
const
node
of
ast
.
nodes
)
{
findNames
(
node
)
}
}
// Handle contracts that are inherited from
if
(
Array
.
isArray
(
ast
.
baseContracts
))
{
for
(
const
baseContract
of
ast
.
baseContracts
)
{
if
(
baseContract
.
baseName
)
{
const
base
=
findContractAndSource
(
baseContract
.
baseName
.
name
,
buildInfo
)
findNames
(
base
.
outputSource
.
ast
)
}
}
}
}
findNames
(
outputSource
.
ast
)
let
deployedBytecode
=
artifact
.
deployedBytecode
const
presize
=
deployedBytecode
.
length
// For each of the immutables, put the value into the bytecode
for
(
const
[
key
,
value
]
of
Object
.
entries
(
immutables
))
{
const
astId
=
names
[
key
]
if
(
!
astId
)
{
throw
new
Error
(
`Unknown immutable
${
key
}
in contract
${
name
}
`
)
}
const
offsets
=
immutableReferences
[
astId
]
if
(
!
offsets
)
{
throw
new
Error
(
`Unknown AST id
${
astId
}
in contract
${
name
}
`
)
}
// Insert the value at each one
for
(
const
offset
of
offsets
)
{
if
(
offset
.
length
!==
32
)
{
throw
new
Error
(
`Immutable slicing must be updated to handle arbitrary size immutables`
)
}
// Ensure that the value being sliced out is 0
const
val
=
hexDataSlice
(
deployedBytecode
,
offset
.
start
,
offset
.
start
+
offset
.
length
)
if
(
!
BigNumber
.
from
(
val
).
eq
(
0
))
{
throw
new
Error
(
`Unexpected value in immutable bytecode
${
val
}
`
)
}
deployedBytecode
=
ethers
.
utils
.
hexConcat
([
hexDataSlice
(
deployedBytecode
,
0
,
offset
.
start
),
hexZeroPad
(
value
,
32
),
hexDataSlice
(
deployedBytecode
,
offset
.
start
+
offset
.
length
),
])
}
}
// Ensure that the bytecode is the same size
if
(
presize
!==
deployedBytecode
.
length
)
{
throw
new
Error
(
`Size mismatch! Before
${
presize
}
, after
${
deployedBytecode
.
length
}
`
)
}
return
deployedBytecode
}
task
(
'
genesis-l2
'
,
'
create a genesis config
'
)
task
(
'
genesis-l2
'
,
'
create a genesis config
'
)
.
addOptionalParam
(
.
addOptionalParam
(
'
outfile
'
,
'
outfile
'
,
...
@@ -138,7 +285,7 @@ task('genesis-l2', 'create a genesis config')
...
@@ -138,7 +285,7 @@ task('genesis-l2', 'create a genesis config')
const
predeployAddrs
=
new
Set
()
const
predeployAddrs
=
new
Set
()
for
(
const
addr
of
Object
.
values
(
predeploys
))
{
for
(
const
addr
of
Object
.
values
(
predeploys
))
{
predeployAddrs
.
add
(
ethers
.
utils
.
getAddress
(
addr
))
predeployAddrs
.
add
(
getAddress
(
addr
))
}
}
const
alloc
:
State
=
{}
const
alloc
:
State
=
{}
...
@@ -146,15 +293,13 @@ task('genesis-l2', 'create a genesis config')
...
@@ -146,15 +293,13 @@ task('genesis-l2', 'create a genesis config')
// Set a proxy at each predeploy address
// Set a proxy at each predeploy address
const
proxy
=
await
hre
.
artifacts
.
readArtifact
(
'
Proxy
'
)
const
proxy
=
await
hre
.
artifacts
.
readArtifact
(
'
Proxy
'
)
for
(
let
i
=
0
;
i
<=
2048
;
i
++
)
{
for
(
let
i
=
0
;
i
<=
2048
;
i
++
)
{
const
num
=
ethers
.
utils
.
hexZeroPad
(
'
0x
'
+
i
.
toString
(
16
),
2
)
const
num
=
hexZeroPad
(
'
0x
'
+
i
.
toString
(
16
),
2
)
const
addr
=
ethers
.
utils
.
getAddress
(
const
addr
=
getAddress
(
ethers
.
utils
.
hexConcat
([
prefix
,
num
]))
ethers
.
utils
.
hexConcat
([
prefix
,
num
])
)
// There is no proxy at LegacyERC20ETH or the GovernanceToken
// There is no proxy at LegacyERC20ETH or the GovernanceToken
if
(
if
(
addr
===
ethers
.
utils
.
getAddress
(
predeploys
.
LegacyERC20ETH
)
||
addr
===
getAddress
(
predeploys
.
LegacyERC20ETH
)
||
addr
===
ethers
.
utils
.
getAddress
(
predeploys
.
GovernanceToken
)
addr
===
getAddress
(
predeploys
.
GovernanceToken
)
)
{
)
{
continue
continue
}
}
...
@@ -168,9 +313,9 @@ task('genesis-l2', 'create a genesis config')
...
@@ -168,9 +313,9 @@ task('genesis-l2', 'create a genesis config')
},
},
}
}
if
(
predeployAddrs
.
has
(
ethers
.
utils
.
getAddress
(
addr
)))
{
if
(
predeployAddrs
.
has
(
getAddress
(
addr
)))
{
const
predeploy
=
Object
.
entries
(
predeploys
).
find
(([,
address
])
=>
{
const
predeploy
=
Object
.
entries
(
predeploys
).
find
(([,
address
])
=>
{
return
ethers
.
utils
.
getAddress
(
address
)
===
addr
return
getAddress
(
address
)
===
addr
})
})
// Really shouldn't happen, since predeployAddrs is a set generated from predeploys.
// Really shouldn't happen, since predeployAddrs is a set generated from predeploys.
...
@@ -211,7 +356,7 @@ task('genesis-l2', 'create a genesis config')
...
@@ -211,7 +356,7 @@ task('genesis-l2', 'create a genesis config')
buf
.
writeUInt16BE
(
i
,
0
)
buf
.
writeUInt16BE
(
i
,
0
)
const
addr
=
ethers
.
utils
.
hexConcat
([
const
addr
=
ethers
.
utils
.
hexConcat
([
'
0x000000000000000000000000000000000000
'
,
'
0x000000000000000000000000000000000000
'
,
ethers
.
utils
.
hexZeroPad
(
buf
,
2
),
hexZeroPad
(
buf
,
2
),
])
])
alloc
[
addr
]
=
{
alloc
[
addr
]
=
{
balance
:
'
0x1
'
,
balance
:
'
0x1
'
,
...
@@ -251,6 +396,44 @@ task('genesis-l2', 'create a genesis config')
...
@@ -251,6 +396,44 @@ task('genesis-l2', 'create a genesis config')
}
}
}
}
// Note: this currently only supports up to 32 byte values.
// Things less than 32 bytes will be left padded with 0 bytes
const
immutables
=
{
OptimismMintableERC20Factory
:
{
bridge
:
predeploys
.
L2StandardBridge
,
},
GasPriceOracle
:
{
MAJOR_VERSION
:
toBytes32
(
0
),
MINOR_VERSION
:
toBytes32
(
0
),
PATCH_VERSION
:
toBytes32
(
1
),
},
L1Block
:
{
MAJOR_VERSION
:
toBytes32
(
0
),
MINOR_VERSION
:
toBytes32
(
0
),
PATCH_VERSION
:
toBytes32
(
1
),
},
L2CrossDomainMessenger
:
{
MAJOR_VERSION
:
toBytes32
(
0
),
MINOR_VERSION
:
toBytes32
(
0
),
PATCH_VERSION
:
toBytes32
(
1
),
},
L2StandardBridge
:
{
MAJOR_VERSION
:
toBytes32
(
0
),
MINOR_VERSION
:
toBytes32
(
0
),
PATCH_VERSION
:
toBytes32
(
1
),
},
L2ToL1MessagePasser
:
{
MAJOR_VERSION
:
toBytes32
(
0
),
MINOR_VERSION
:
toBytes32
(
0
),
PATCH_VERSION
:
toBytes32
(
1
),
},
SequencerFeeVault
:
{
MAJOR_VERSION
:
toBytes32
(
0
),
MINOR_VERSION
:
toBytes32
(
0
),
PATCH_VERSION
:
toBytes32
(
1
),
},
}
// Set the predeploys in the state
// Set the predeploys in the state
for
(
const
[
name
,
addr
]
of
Object
.
entries
(
predeploys
))
{
for
(
const
[
name
,
addr
]
of
Object
.
entries
(
predeploys
))
{
if
(
name
===
'
GovernanceToken
'
)
{
if
(
name
===
'
GovernanceToken
'
)
{
...
@@ -262,10 +445,19 @@ task('genesis-l2', 'create a genesis config')
...
@@ -262,10 +445,19 @@ task('genesis-l2', 'create a genesis config')
const
allocAddr
=
name
===
'
LegacyERC20ETH
'
?
addr
:
toCodeAddr
(
addr
)
const
allocAddr
=
name
===
'
LegacyERC20ETH
'
?
addr
:
toCodeAddr
(
addr
)
assertEvenLength
(
allocAddr
)
assertEvenLength
(
allocAddr
)
const
immutableConfig
=
immutables
[
name
]
const
deployedBytecode
=
immutableConfig
?
await
replaceImmutables
(
hre
,
name
,
immutableConfig
)
:
artifact
.
deployedBytecode
assertEvenLength
(
deployedBytecode
)
// TODO(tynes): initialize contracts that should be initialized
// in the implementations here
alloc
[
allocAddr
]
=
{
alloc
[
allocAddr
]
=
{
nonce
:
'
0x00
'
,
nonce
:
'
0x00
'
,
balance
:
'
0x00
'
,
balance
:
'
0x00
'
,
code
:
artifact
.
deployedBytecode
,
code
:
deployedBytecode
,
storage
:
{},
storage
:
{},
}
}
}
}
...
@@ -273,6 +465,12 @@ task('genesis-l2', 'create a genesis config')
...
@@ -273,6 +465,12 @@ task('genesis-l2', 'create a genesis config')
const
portal
=
await
hre
.
deployments
.
get
(
'
OptimismPortalProxy
'
)
const
portal
=
await
hre
.
deployments
.
get
(
'
OptimismPortalProxy
'
)
const
l1StartingBlock
=
await
l1
.
getBlock
(
portal
.
receipt
.
blockHash
)
const
l1StartingBlock
=
await
l1
.
getBlock
(
portal
.
receipt
.
blockHash
)
if
(
l1StartingBlock
===
null
)
{
console
.
log
(
`Unable to fetch L1 starting timestamp`
)
}
const
startingTimestamp
=
l1StartingBlock
?.
timestamp
||
0
const
genesis
:
OptimismGenesis
=
{
const
genesis
:
OptimismGenesis
=
{
config
:
{
config
:
{
chainId
:
deployConfig
.
genesisBlockChainid
,
chainId
:
deployConfig
.
genesisBlockChainid
,
...
@@ -296,7 +494,7 @@ task('genesis-l2', 'create a genesis config')
...
@@ -296,7 +494,7 @@ task('genesis-l2', 'create a genesis config')
},
},
nonce
:
'
0x1234
'
,
nonce
:
'
0x1234
'
,
difficulty
:
'
0x1
'
,
difficulty
:
'
0x1
'
,
timestamp
:
ethers
.
BigNumber
.
from
(
l1StartingBlock
.
t
imestamp
).
toHexString
(),
timestamp
:
ethers
.
BigNumber
.
from
(
startingT
imestamp
).
toHexString
(),
gasLimit
:
deployConfig
.
genesisBlockGasLimit
,
gasLimit
:
deployConfig
.
genesisBlockGasLimit
,
extraData
:
deployConfig
.
genesisBlockExtradata
,
extraData
:
deployConfig
.
genesisBlockExtradata
,
alloc
,
alloc
,
...
...
This diff is collapsed.
Click to expand it.
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