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
c1e7f122
Unverified
Commit
c1e7f122
authored
Nov 29, 2022
by
mergify[bot]
Committed by
GitHub
Nov 29, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4078 from ethereum-optimism/feat/receipts
op-chain-ops: add bedrock transition receipts
parents
1366092e
7d2fa734
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
205 additions
and
45 deletions
+205
-45
legacy_withdrawal.go
op-chain-ops/crossdomain/legacy_withdrawal.go
+44
-0
migrate.go
op-chain-ops/crossdomain/migrate.go
+7
-39
migrate_test.go
op-chain-ops/crossdomain/migrate_test.go
+1
-3
types.go
op-chain-ops/crossdomain/types.go
+1
-0
withdrawal.go
op-chain-ops/crossdomain/withdrawal.go
+115
-0
db_migration.go
op-chain-ops/genesis/db_migration.go
+8
-3
receipts.go
op-chain-ops/genesis/receipts.go
+29
-0
No files found.
op-chain-ops/crossdomain/legacy_withdrawal.go
View file @
c1e7f122
...
...
@@ -6,6 +6,7 @@ import (
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -126,3 +127,46 @@ func (w *LegacyWithdrawal) StorageSlot() (common.Hash, error) {
slot
:=
crypto
.
Keccak256
(
preimage
)
return
common
.
BytesToHash
(
slot
),
nil
}
// Value returns the ETH value associated with the withdrawal. Since
// ETH was represented as an ERC20 token before the Bedrock upgrade,
// the sender and calldata must be observed and the value must be parsed
// out if "finalizeETHWithdrawal" is the method.
func
(
w
*
LegacyWithdrawal
)
Value
()
(
*
big
.
Int
,
error
)
{
abi
,
err
:=
bindings
.
L1StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
value
:=
new
(
big
.
Int
)
// Parse the 4byte selector
method
,
err
:=
abi
.
MethodById
(
w
.
Data
)
// If it is an unknown selector, there is no value
if
err
!=
nil
{
return
value
,
nil
}
if
w
.
Sender
==
nil
{
return
nil
,
errors
.
New
(
"sender is nil"
)
}
isFromL2StandardBridge
:=
*
w
.
Sender
==
predeploys
.
L2StandardBridgeAddr
if
isFromL2StandardBridge
&&
method
.
Name
==
"finalizeETHWithdrawal"
{
data
,
err
:=
method
.
Inputs
.
Unpack
(
w
.
Data
[
4
:
])
if
err
!=
nil
{
return
nil
,
err
}
// bounds check
if
len
(
data
)
<
3
{
return
nil
,
errors
.
New
(
"not enough data"
)
}
var
ok
bool
value
,
ok
=
data
[
2
]
.
(
*
big
.
Int
)
if
!
ok
{
return
nil
,
errors
.
New
(
"not big.Int"
)
}
}
return
value
,
nil
}
op-chain-ops/crossdomain/migrate.go
View file @
c1e7f122
package
crossdomain
import
(
"errors"
"fmt"
"math/big"
...
...
@@ -19,7 +18,7 @@ var (
)
// MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB.
func
MigrateWithdrawals
(
withdrawals
[]
*
LegacyWithdrawal
,
db
vm
.
StateDB
,
l1CrossDomainMessenger
,
l1StandardBridge
*
common
.
Address
)
error
{
func
MigrateWithdrawals
(
withdrawals
[]
*
LegacyWithdrawal
,
db
vm
.
StateDB
,
l1CrossDomainMessenger
*
common
.
Address
)
error
{
for
i
,
legacy
:=
range
withdrawals
{
legacySlot
,
err
:=
legacy
.
StorageSlot
()
if
err
!=
nil
{
...
...
@@ -36,7 +35,7 @@ func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossD
continue
}
withdrawal
,
err
:=
MigrateWithdrawal
(
legacy
,
l1CrossDomainMessenger
,
l1StandardBridge
)
withdrawal
,
err
:=
MigrateWithdrawal
(
legacy
,
l1CrossDomainMessenger
)
if
err
!=
nil
{
return
err
}
...
...
@@ -54,42 +53,11 @@ func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossD
// MigrateWithdrawal will turn a LegacyWithdrawal into a bedrock
// style Withdrawal.
func
MigrateWithdrawal
(
withdrawal
*
LegacyWithdrawal
,
l1CrossDomainMessenger
,
l1StandardBridge
*
common
.
Address
)
(
*
Withdrawal
,
error
)
{
value
:=
new
(
big
.
Int
)
isFromL2StandardBridge
:=
*
withdrawal
.
Sender
==
predeploys
.
L2StandardBridgeAddr
if
withdrawal
.
Target
==
nil
{
return
nil
,
errors
.
New
(
"withdrawal target cannot be nil"
)
}
isToL1StandardBridge
:=
*
withdrawal
.
Target
==
*
l1StandardBridge
if
isFromL2StandardBridge
&&
isToL1StandardBridge
{
abi
,
err
:=
bindings
.
L1StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
return
nil
,
err
}
method
,
err
:=
abi
.
MethodById
(
withdrawal
.
Data
)
if
err
!=
nil
{
return
nil
,
err
}
if
method
.
Name
==
"finalizeETHWithdrawal"
{
data
,
err
:=
method
.
Inputs
.
Unpack
(
withdrawal
.
Data
[
4
:
])
if
err
!=
nil
{
return
nil
,
err
}
// bounds check
if
len
(
data
)
<
3
{
return
nil
,
errors
.
New
(
"not enough data"
)
}
var
ok
bool
value
,
ok
=
data
[
2
]
.
(
*
big
.
Int
)
if
!
ok
{
return
nil
,
errors
.
New
(
"not big.Int"
)
}
}
func
MigrateWithdrawal
(
withdrawal
*
LegacyWithdrawal
,
l1CrossDomainMessenger
*
common
.
Address
)
(
*
Withdrawal
,
error
)
{
// Attempt to parse the value
value
,
err
:=
withdrawal
.
Value
()
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot migrate withdrawal: %w"
,
err
)
}
abi
,
err
:=
bindings
.
L1CrossDomainMessengerMetaData
.
GetAbi
()
...
...
op-chain-ops/crossdomain/migrate_test.go
View file @
c1e7f122
...
...
@@ -25,11 +25,9 @@ func TestMigrateWithdrawal(t *testing.T) {
}
l1CrossDomainMessenger
:=
common
.
HexToAddress
(
"0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1"
)
l1StandardBridge
:=
common
.
HexToAddress
(
"0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1"
)
for
i
,
legacy
:=
range
withdrawals
{
t
.
Run
(
fmt
.
Sprintf
(
"test%d"
,
i
),
func
(
t
*
testing
.
T
)
{
withdrawal
,
err
:=
crossdomain
.
MigrateWithdrawal
(
legacy
,
&
l1CrossDomainMessenger
,
&
l1StandardBridge
)
withdrawal
,
err
:=
crossdomain
.
MigrateWithdrawal
(
legacy
,
&
l1CrossDomainMessenger
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
withdrawal
)
...
...
op-chain-ops/crossdomain/types.go
View file @
c1e7f122
...
...
@@ -10,6 +10,7 @@ var (
Uint256Type
,
_
=
abi
.
NewType
(
"uint256"
,
""
,
nil
)
BytesType
,
_
=
abi
.
NewType
(
"bytes"
,
""
,
nil
)
AddressType
,
_
=
abi
.
NewType
(
"address"
,
""
,
nil
)
Bytes32Type
,
_
=
abi
.
NewType
(
"bytes32"
,
""
,
nil
)
)
// WithdrawalMessage represents a Withdrawal. The Withdrawal
...
...
op-chain-ops/crossdomain/withdrawal.go
View file @
c1e7f122
...
...
@@ -4,11 +4,22 @@ import (
"errors"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)
var
(
SentMessageEventABI
=
"SentMessage(address,address,bytes,uint256)"
SentMessageEventABIHash
=
crypto
.
Keccak256Hash
([]
byte
(
SentMessageEventABI
))
SentMessageExtension1EventABI
=
"SentMessage(address,uint256)"
SentMessageExtension1EventABIHash
=
crypto
.
Keccak256Hash
([]
byte
(
SentMessageExtension1EventABI
))
MessagePassedEventABI
=
"MessagePassed(uint256,address,address,uint256,uint256,bytes,bytes32)"
MessagePassedEventABIHash
=
crypto
.
Keccak256Hash
([]
byte
(
MessagePassedEventABI
))
)
var
_
WithdrawalMessage
=
(
*
Withdrawal
)(
nil
)
// Withdrawal represents a withdrawal transaction on L2
...
...
@@ -130,3 +141,107 @@ func (w *Withdrawal) StorageSlot() (common.Hash, error) {
slot
:=
crypto
.
Keccak256
(
preimage
)
return
common
.
BytesToHash
(
slot
),
nil
}
// Compute the receipt corresponding to the withdrawal. This receipt
// is in the bedrock transition block. It contains 3 logs.
// SentMessage, SentMessageExtension1 and MessagePassed.
// These logs are enough for the standard withdrawal flow to happen
// which is driven by events being emitted.
func
(
w
*
Withdrawal
)
Receipt
(
hdr
*
types
.
Header
,
txIndex
uint
)
(
*
types
.
Receipt
,
error
)
{
// Create a new receipt with the state root, successful execution and no gas
// used
receipt
:=
types
.
NewReceipt
(
hdr
.
Root
.
Bytes
(),
false
,
0
)
if
receipt
.
Logs
==
nil
{
receipt
.
Logs
=
make
([]
*
types
.
Log
,
0
)
}
// Use a counter to track the log index. Each receipt has 3 events and there
// is 1 receipt per transaction. Increment the logIndex after appending the
// log to the receipt.
logIndex
:=
txIndex
*
3
// Create the SentMessage log.
args
:=
abi
.
Arguments
{
{
Name
:
"target"
,
Type
:
AddressType
},
{
Name
:
"sender"
,
Type
:
AddressType
},
{
Name
:
"data"
,
Type
:
BytesType
},
{
Name
:
"nonce"
,
Type
:
Uint256Type
},
}
data
,
err
:=
args
.
Pack
(
w
.
Target
,
w
.
Sender
,
w
.
Data
,
w
.
Nonce
)
if
err
!=
nil
{
return
nil
,
err
}
// The L2CrossDomainMessenger emits this event. The target is
// indexed.
sm
:=
&
types
.
Log
{
Address
:
predeploys
.
L2CrossDomainMessengerAddr
,
Topics
:
[]
common
.
Hash
{
SentMessageEventABIHash
,
w
.
Target
.
Hash
(),
},
Data
:
data
,
BlockNumber
:
hdr
.
Number
.
Uint64
(),
TxHash
:
common
.
Hash
{},
TxIndex
:
txIndex
,
BlockHash
:
hdr
.
Hash
(),
Index
:
logIndex
,
Removed
:
false
,
}
receipt
.
Logs
=
append
(
receipt
.
Logs
,
sm
)
logIndex
++
// Create the SentMessageExtension1 log. The L2CrossDomainMessenger
// emits this event. The sender is indexed.
sm1
:=
&
types
.
Log
{
Address
:
predeploys
.
L2CrossDomainMessengerAddr
,
Topics
:
[]
common
.
Hash
{
SentMessageExtension1EventABIHash
,
w
.
Sender
.
Hash
(),
},
Data
:
common
.
LeftPadBytes
(
w
.
Value
.
Bytes
(),
32
),
BlockNumber
:
hdr
.
Number
.
Uint64
(),
TxHash
:
common
.
Hash
{},
TxIndex
:
txIndex
,
BlockHash
:
hdr
.
Hash
(),
Index
:
logIndex
,
Removed
:
false
,
}
receipt
.
Logs
=
append
(
receipt
.
Logs
,
sm1
)
logIndex
++
// Create the MessagePassed log.
mpargs
:=
abi
.
Arguments
{
{
Name
:
"value"
,
Type
:
Uint256Type
},
{
Name
:
"gasLimit"
,
Type
:
Uint256Type
},
{
Name
:
"data"
,
Type
:
BytesType
},
{
Name
:
"withdrawalHash"
,
Type
:
Bytes32Type
},
}
hash
,
err
:=
w
.
Hash
()
if
err
!=
nil
{
return
nil
,
err
}
mpdata
,
err
:=
mpargs
.
Pack
(
w
.
Value
,
w
.
GasLimit
,
w
.
Data
,
hash
)
if
err
!=
nil
{
return
nil
,
err
}
// The L2ToL1MessagePasser emits this event.
mp
:=
&
types
.
Log
{
Address
:
predeploys
.
L2ToL1MessagePasserAddr
,
Topics
:
[]
common
.
Hash
{
MessagePassedEventABIHash
,
common
.
BytesToHash
(
common
.
LeftPadBytes
(
w
.
Nonce
.
Bytes
(),
32
)),
w
.
Sender
.
Hash
(),
w
.
Target
.
Hash
(),
},
Data
:
mpdata
,
BlockNumber
:
hdr
.
Number
.
Uint64
(),
TxHash
:
common
.
Hash
{},
TxIndex
:
txIndex
,
BlockHash
:
hdr
.
Hash
(),
Index
:
logIndex
,
Removed
:
false
,
}
receipt
.
Logs
=
append
(
receipt
.
Logs
,
mp
)
return
receipt
,
nil
}
op-chain-ops/genesis/db_migration.go
View file @
c1e7f122
...
...
@@ -80,7 +80,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
}
log
.
Info
(
"Starting to migrate withdrawals"
)
err
=
crossdomain
.
MigrateWithdrawals
(
withdrawals
,
db
,
&
config
.
L1CrossDomainMessengerProxy
,
&
config
.
L1StandardBridgeProxy
)
err
=
crossdomain
.
MigrateWithdrawals
(
withdrawals
,
db
,
&
config
.
L1CrossDomainMessengerProxy
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot migrate withdrawals: %w"
,
err
)
}
...
...
@@ -115,7 +115,12 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
BaseFee
:
(
*
big
.
Int
)(
config
.
L2GenesisBlockBaseFeePerGas
),
}
bedrockBlock
:=
types
.
NewBlock
(
bedrockHeader
,
nil
,
nil
,
nil
,
trie
.
NewStackTrie
(
nil
))
receipts
,
err
:=
CreateReceipts
(
bedrockHeader
,
withdrawals
,
&
config
.
L1CrossDomainMessengerProxy
)
if
err
!=
nil
{
return
nil
,
err
}
bedrockBlock
:=
types
.
NewBlock
(
bedrockHeader
,
nil
,
nil
,
receipts
,
trie
.
NewStackTrie
(
nil
))
res
:=
&
MigrationResult
{
TransitionHeight
:
bedrockBlock
.
NumberU64
(),
...
...
@@ -130,7 +135,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
rawdb
.
WriteTd
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
(),
bedrockBlock
.
Difficulty
())
rawdb
.
WriteBlock
(
ldb
,
bedrockBlock
)
rawdb
.
WriteReceipts
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
(),
nil
)
rawdb
.
WriteReceipts
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
(),
receipts
)
rawdb
.
WriteCanonicalHash
(
ldb
,
bedrockBlock
.
Hash
(),
bedrockBlock
.
NumberU64
())
rawdb
.
WriteHeadBlockHash
(
ldb
,
bedrockBlock
.
Hash
())
rawdb
.
WriteHeadFastBlockHash
(
ldb
,
bedrockBlock
.
Hash
())
...
...
op-chain-ops/genesis/receipts.go
0 → 100644
View file @
c1e7f122
package
genesis
import
(
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// CreateReceipts will create the set of bedrock genesis receipts given
// a list of legacy withdrawals.
func
CreateReceipts
(
hdr
*
types
.
Header
,
withdrawals
[]
*
crossdomain
.
LegacyWithdrawal
,
l1CrossDomainMessenger
*
common
.
Address
)
([]
*
types
.
Receipt
,
error
)
{
receipts
:=
make
([]
*
types
.
Receipt
,
0
)
for
i
,
withdrawal
:=
range
withdrawals
{
wd
,
err
:=
crossdomain
.
MigrateWithdrawal
(
withdrawal
,
l1CrossDomainMessenger
)
if
err
!=
nil
{
return
nil
,
err
}
receipt
,
err
:=
wd
.
Receipt
(
hdr
,
uint
(
i
))
if
err
!=
nil
{
return
nil
,
err
}
receipts
=
append
(
receipts
,
receipt
)
}
return
receipts
,
nil
}
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