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
b2242f40
Commit
b2242f40
authored
Dec 20, 2022
by
Mark Tyneway
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-chain-ops: more fixes
parent
de9a9a16
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
566 additions
and
319 deletions
+566
-319
main.go
op-chain-ops/cmd/withdrawals/main.go
+556
-316
legacy_withdrawal.go
op-chain-ops/crossdomain/legacy_withdrawal.go
+4
-3
message.go
op-chain-ops/crossdomain/message.go
+6
-0
No files found.
op-chain-ops/cmd/withdrawals/main.go
View file @
b2242f40
...
...
@@ -17,6 +17,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
...
...
@@ -31,6 +32,8 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)
var
abiTrue
=
common
.
Hash
{
31
:
0x01
}
// callFrame represents the response returned from geth's
// `debug_traceTransaction` callTracer
type
callFrame
struct
{
...
...
@@ -46,6 +49,20 @@ type callFrame struct {
Calls
[]
callFrame
`json:"calls,omitempty"`
}
func
(
c
*
callFrame
)
BigValue
()
*
big
.
Int
{
v
:=
strings
.
TrimPrefix
(
c
.
Value
,
"0x"
)
b
,
_
:=
new
(
big
.
Int
)
.
SetString
(
v
,
16
)
return
b
}
type
suspiciousWithdrawal
struct
{
Withdrawal
*
crossdomain
.
Withdrawal
`json:"withdrawal"`
Legacy
*
crossdomain
.
LegacyWithdrawal
`json:"legacy"`
Trace
callFrame
`json:"trace"`
Index
int
`json:"index"`
Reason
string
`json:"reason"`
}
// findWithdrawalCall will find the call frame for the call that
// represents the user's intent.
func
findWithdrawalCall
(
trace
*
callFrame
,
wd
*
crossdomain
.
LegacyWithdrawal
,
l1xdm
common
.
Address
)
*
callFrame
{
...
...
@@ -69,8 +86,7 @@ func createOutput(
withdrawal
*
crossdomain
.
Withdrawal
,
oracle
*
bindings
.
L2OutputOracle
,
blockNumber
*
big
.
Int
,
l2Client
bind
.
ContractBackend
,
l2GethClient
*
gethclient
.
Client
,
clients
*
clients
,
)
(
*
big
.
Int
,
bindings
.
TypesOutputRootProof
,
[][]
byte
,
error
)
{
// compute the storage slot that the withdrawal is stored in
slot
,
err
:=
withdrawal
.
StorageSlot
()
...
...
@@ -78,7 +94,7 @@ func createOutput(
return
nil
,
bindings
.
TypesOutputRootProof
{},
nil
,
err
}
// find the output index that the withdrawal was commited to in
// find the output index that the withdrawal was commit
t
ed to in
l2OutputIndex
,
err
:=
oracle
.
GetL2OutputIndexAfter
(
&
bind
.
CallOpts
{},
blockNumber
)
if
err
!=
nil
{
return
nil
,
bindings
.
TypesOutputRootProof
{},
nil
,
err
...
...
@@ -98,13 +114,14 @@ func createOutput(
)
// get the block header committed to in the output
header
,
err
:=
l
2Client
.
HeaderByNumber
(
context
.
Background
(),
l2Output
.
L2BlockNumber
)
header
,
err
:=
clients
.
L
2Client
.
HeaderByNumber
(
context
.
Background
(),
l2Output
.
L2BlockNumber
)
if
err
!=
nil
{
return
nil
,
bindings
.
TypesOutputRootProof
{},
nil
,
err
}
// get the storage proof for the withdrawal's storage slot
proof
,
err
:=
l2GethClient
.
GetProof
(
context
.
Background
(),
predeploys
.
L2ToL1MessagePasserAddr
,
[]
string
{
slot
.
String
()},
blockNumber
)
proof
,
err
:=
clients
.
L2GethClient
.
GetProof
(
context
.
Background
(),
predeploys
.
L2ToL1MessagePasserAddr
,
[]
string
{
slot
.
String
()},
blockNumber
)
if
err
!=
nil
{
return
nil
,
bindings
.
TypesOutputRootProof
{},
nil
,
err
}
...
...
@@ -124,7 +141,6 @@ func createOutput(
LatestBlockhash
:
header
.
Hash
(),
}
// compute a storage root hash locally
localOutputRootHash
:=
crypto
.
Keccak256Hash
(
outputRootProof
.
Version
[
:
],
outputRootProof
.
StateRoot
[
:
],
...
...
@@ -134,7 +150,7 @@ func createOutput(
// ensure that the locally computed hash matches
if
l2Output
.
OutputRoot
!=
localOutputRootHash
{
return
nil
,
bindings
.
TypesOutputRootProof
{},
nil
,
fmt
.
Errorf
(
"mismatch in output root hashes
"
,
"got"
,
localOutputRootHash
,
"expect"
,
l2Output
.
OutputRoot
)
return
nil
,
bindings
.
TypesOutputRootProof
{},
nil
,
fmt
.
Errorf
(
"mismatch in output root hashes
, got 0x%x expected 0x%x"
,
localOutputRootHash
,
l2Output
.
OutputRoot
)
}
log
.
Info
(
"output root proof"
,
...
...
@@ -142,6 +158,7 @@ func createOutput(
"state-root"
,
common
.
Hash
(
outputRootProof
.
StateRoot
),
"storage-root"
,
common
.
Hash
(
outputRootProof
.
MessagePasserStorageRoot
),
"block-hash"
,
common
.
Hash
(
outputRootProof
.
LatestBlockhash
),
"trie-node-count"
,
len
(
trieNodes
),
)
return
l2OutputIndex
,
outputRootProof
,
trieNodes
,
nil
...
...
@@ -184,10 +201,6 @@ func main() {
Name
:
"evm-messages"
,
Usage
:
"Path to evm-messages.json"
,
},
&
cli
.
Uint64Flag
{
Name
:
"bedrock-transition-block-number"
,
Usage
:
"The blocknumber of the bedrock transition block"
,
},
&
cli
.
StringFlag
{
Name
:
"private-key"
,
Usage
:
"Key to sign transactions with"
,
...
...
@@ -199,303 +212,212 @@ func main() {
},
},
Action
:
func
(
ctx
*
cli
.
Context
)
error
{
// set up the rpc clients
l1RpcURL
:=
ctx
.
String
(
"l1-rpc-url"
)
l1Client
,
err
:=
ethclient
.
Dial
(
l1RpcURL
)
if
err
!=
nil
{
return
err
}
l1ChainID
,
err
:=
l1Client
.
ChainID
(
context
.
Background
())
clients
,
err
:=
newClients
(
ctx
)
if
err
!=
nil
{
return
err
}
log
.
Info
(
"Set up L1 RPC Client"
,
"chain-id"
,
l1ChainID
)
l2RpcURL
:=
ctx
.
String
(
"l2-rpc-url"
)
l2Client
,
err
:=
ethclient
.
Dial
(
l2RpcURL
)
// initialize the contract bindings
contracts
,
err
:=
newContracts
(
ctx
,
clients
.
L1Client
,
clients
.
L2Client
)
if
err
!=
nil
{
return
err
}
l2ChainID
,
err
:=
l2Client
.
ChainID
(
context
.
Background
())
if
err
!=
nil
{
return
err
}
log
.
Info
(
"Set up L2 RPC Client"
,
"chain-id"
,
l2ChainID
)
l1xdmAddr
:=
common
.
HexToAddress
(
ctx
.
String
(
"l1-crossdomain-messenger-address"
))
l1
RpcClient
,
err
:=
rpc
.
DialContext
(
context
.
Background
(),
l1RpcURL
)
l1
ChainID
,
err
:=
clients
.
L1Client
.
ChainID
(
context
.
Background
()
)
if
err
!=
nil
{
return
err
}
l2RpcClient
,
err
:=
rpc
.
DialContext
(
context
.
Background
(),
l2RpcURL
)
// create the set of withdrawals
wds
,
err
:=
newWithdrawals
(
ctx
,
l1ChainID
)
if
err
!=
nil
{
return
err
}
// this script requires geth's rpcs
gclient
:=
gethclient
.
New
(
l2RpcClient
)
// get the evm and ovm messages witness files used as part of
// migration
ovmMsgs
:=
ctx
.
String
(
"ovm-messages"
)
evmMsgs
:=
ctx
.
String
(
"evm-messages"
)
log
.
Debug
(
"Migration data"
,
"ovm-path"
,
ovmMsgs
,
"evm-messages"
,
evmMsgs
)
ovmMessages
,
err
:=
migration
.
NewSentMessage
(
ovmMsgs
)
if
err
!=
nil
{
return
err
}
evmMessages
,
err
:=
migration
.
NewSentMessage
(
evmMsgs
)
period
,
err
:=
contracts
.
OptimismPortal
.
FINALIZATIONPERIODSECONDS
(
&
bind
.
CallOpts
{})
if
err
!=
nil
{
return
err
}
optimismPortalAddress
:=
ctx
.
String
(
"optimism-portal-address"
)
if
len
(
optimismPortalAddress
)
==
0
{
return
errors
.
New
(
"OptimismPortal address not configured"
)
}
optimismPortalAddr
:=
common
.
HexToAddress
(
optimismPortalAddress
)
migrationData
:=
migration
.
MigrationData
{
OvmMessages
:
ovmMessages
,
EvmMessages
:
evmMessages
,
}
// create the set of withdrawals
wds
,
err
:=
migrationData
.
ToWithdrawals
()
bedrockStartingBlockNumber
,
err
:=
contracts
.
L2OutputOracle
.
StartingBlockNumber
(
&
bind
.
CallOpts
{})
if
err
!=
nil
{
return
err
}
if
len
(
wds
)
==
0
{
return
errors
.
New
(
"no withdrawals"
)
}
log
.
Info
(
"Converted migration data to withdrawals successfully"
,
"count"
,
len
(
wds
))
l1xdmAddress
:=
ctx
.
String
(
"l1-crossdomain-messenger-address"
)
if
l1xdmAddress
==
""
{
return
errors
.
New
(
"Must pass in --l1-crossdomain-messenger-address"
)
}
l1xdmAddr
:=
common
.
HexToAddress
(
l1xdmAddress
)
bedrockStartingBlock
,
err
:=
clients
.
L2Client
.
BlockByNumber
(
context
.
Background
(),
bedrockStartingBlockNumber
)
l1CrossDomainMessenger
,
err
:=
bindings
.
NewL1CrossDomainMessenger
(
l1xdmAddr
,
l1Client
)
if
err
!=
nil
{
return
err
}
log
.
Info
(
"Withdrawal config"
,
"finalization-period"
,
period
,
"bedrock-starting-block-number"
,
bedrockStartingBlockNumber
,
"bedrock-starting-block-hash"
,
bedrockStartingBlock
.
Hash
()
.
Hex
())
portal
,
err
:=
bindings
.
NewOptimismPortal
(
optimismPortalAddr
,
l1Client
)
if
err
!=
nil
{
return
err
if
!
bytes
.
Equal
(
bedrockStartingBlock
.
Extra
(),
genesis
.
BedrockTransitionBlockExtraData
)
{
return
errors
.
New
(
"genesis block mismatch"
)
}
l2OracleAddr
,
err
:=
portal
.
L2ORACLE
(
&
bind
.
CallOpts
{})
outfile
:=
ctx
.
String
(
"bad-withdrawals-out"
)
f
,
err
:=
os
.
OpenFile
(
outfile
,
os
.
O_WRONLY
|
os
.
O_CREATE
|
os
.
O_APPEND
,
0
o755
)
if
err
!=
nil
{
return
err
}
oracle
,
err
:=
bindings
.
NewL2OutputOracle
(
l2OracleAddr
,
l1Client
)
if
err
!=
nil
{
return
nil
}
log
.
Info
(
"Addresses"
,
"l1-crossdomain-messenger"
,
l1xdmAddr
,
"optimism-portal"
,
optimismPortalAddr
,
"output-oracle"
,
l2OracleAddr
,
)
period
,
err
:=
portal
.
FINALIZATIONPERIODSECONDS
(
&
bind
.
CallOpts
{})
if
err
!=
nil
{
return
err
}
transitionBlockNumber
:=
new
(
big
.
Int
)
.
SetUint64
(
ctx
.
Uint64
(
"bedrock-transition-block-number"
))
log
.
Info
(
"Withdrawal config"
,
"finalization-period"
,
period
,
"bedrock-transition-block-number"
,
transitionBlockNumber
)
if
ctx
.
String
(
"private-key"
)
==
""
{
return
errors
.
New
(
"No private key to transact with"
)
}
privateKey
,
err
:=
crypto
.
HexToECDSA
(
strings
.
TrimPrefix
(
ctx
.
String
(
"private-key"
),
"0x"
))
// create a transactor
opts
,
err
:=
newTransactor
(
ctx
)
if
err
!=
nil
{
return
err
}
type
badWithdrawal
struct
{
Withdrawal
*
crossdomain
.
Withdrawal
`json:"withdrawal"`
Legacy
*
crossdomain
.
LegacyWithdrawal
`json:"legacy"`
Trace
callFrame
`json:"trace"`
Index
int
`json"index"`
}
badWithdrawals
:=
make
([]
badWithdrawal
,
0
)
// Need this to compare in event parsing
l1StandardBridgeAddress
:=
common
.
HexToAddress
(
ctx
.
String
(
"l1-standard-bridge-address"
))
// iterate over all of the withdrawals and submit them
for
i
,
wd
:=
range
wds
{
log
.
Info
(
"Processing withdrawal"
,
"index"
,
i
)
// migrate the withdrawal
withdrawal
,
err
:=
crossdomain
.
MigrateWithdrawal
(
wd
,
&
l1xdmAddr
)
if
err
!=
nil
{
return
err
}
// compute the withdrawal hash
// Pass to Portal
hash
,
err
:=
withdrawal
.
Hash
()
if
err
!=
nil
{
return
err
}
lcdm
:=
wd
.
CrossDomainMessage
()
legacyXdmHash
,
err
:=
lcdm
.
Hash
()
if
err
!=
nil
{
return
err
}
// check to see if the withdrawal has already been successfully
// relayed or received
isSuccess
,
err
:=
l1CrossDomainMessenger
.
SuccessfulMessages
(
&
bind
.
CallOpts
{},
h
ash
)
isSuccess
,
err
:=
contracts
.
L1CrossDomainMessenger
.
SuccessfulMessages
(
&
bind
.
CallOpts
{},
legacyXdmH
ash
)
if
err
!=
nil
{
return
err
}
is
Received
,
err
:=
l1CrossDomainMessenger
.
ReceivedMessages
(
&
bind
.
CallOpts
{},
h
ash
)
is
Failed
,
err
:=
contracts
.
L1CrossDomainMessenger
.
FailedMessages
(
&
bind
.
CallOpts
{},
legacyXdmH
ash
)
if
err
!=
nil
{
return
err
}
// compute the storage slot
slot
,
err
:=
withdrawal
.
StorageSlot
()
// This is just wrong
xdmHash
:=
crypto
.
Keccak256Hash
(
withdrawal
.
Data
)
if
err
!=
nil
{
return
err
}
isSuccessNew
,
err
:=
contracts
.
L1CrossDomainMessenger
.
SuccessfulMessages
(
&
bind
.
CallOpts
{},
xdmHash
)
if
err
!=
nil
{
return
err
}
isFailedNew
,
err
:=
contracts
.
L1CrossDomainMessenger
.
FailedMessages
(
&
bind
.
CallOpts
{},
xdmHash
)
if
err
!=
nil
{
return
err
}
log
.
Info
(
"cross domain messenger status"
,
"hash"
,
hash
.
Hex
(),
"success"
,
isSuccess
,
"received"
,
isReceived
,
"slot"
,
slot
.
Hex
()
)
log
.
Info
(
"cross domain messenger status"
,
"hash"
,
legacyXdmHash
.
Hex
(),
"success"
,
isSuccess
,
"failed"
,
isFailed
,
"is-success-new"
,
isSuccessNew
,
"is-failed-new"
,
isFailedNew
)
// compute the storage slot
slot
,
err
:=
withdrawal
.
StorageSlot
()
if
err
!=
nil
{
return
err
}
// successful messages can be skipped, received messages failed
// their execution and should be replayed
if
isSuccess
{
if
isSuccess
New
{
log
.
Info
(
"Message already relayed"
,
"index"
,
i
,
"hash"
,
hash
,
"slot"
,
slot
)
continue
}
// create the values required for submitting a proof
l2OutputIndex
,
outputRootProof
,
trieNodes
,
err
:=
createOutput
(
withdrawal
,
oracle
,
transitionBlockNumber
,
l2Client
,
gclient
)
// check the storage value of the slot to ensure that it is in
// the L2 storage. Without this check, the proof will fail
storageValue
,
err
:=
clients
.
L2Client
.
StorageAt
(
context
.
Background
(),
predeploys
.
L2ToL1MessagePasserAddr
,
slot
,
nil
)
if
err
!=
nil
{
return
err
}
log
.
Debug
(
"L2ToL1MessagePasser status"
,
"value"
,
common
.
Bytes2Hex
(
storageValue
))
opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
privateKey
,
l1ChainID
)
// the value should be set to a boolean in storage
if
!
bytes
.
Equal
(
storageValue
,
abiTrue
.
Bytes
())
{
return
fmt
.
Errorf
(
"storage slot %x not found in state"
,
slot
)
}
legacySlot
,
err
:=
wd
.
StorageSlot
()
if
err
!=
nil
{
return
err
}
legacyStorageValue
,
err
:=
clients
.
L2Client
.
StorageAt
(
context
.
Background
(),
predeploys
.
LegacyMessagePasserAddr
,
legacySlot
,
nil
)
if
err
!=
nil
{
return
err
}
log
.
Debug
(
"LegacyMessagePasser status"
,
"value"
,
common
.
Bytes2Hex
(
legacyStorageValue
))
// check to see if its already been proven
proven
,
err
:=
p
ortal
.
ProvenWithdrawals
(
&
bind
.
CallOpts
{},
hash
)
proven
,
err
:=
contracts
.
OptimismP
ortal
.
ProvenWithdrawals
(
&
bind
.
CallOpts
{},
hash
)
if
err
!=
nil
{
return
err
}
wdTx
:=
withdrawal
.
WithdrawalTransaction
()
// check to see if its been proven
// if it has not been proven, then prove it
if
proven
.
Timestamp
.
Cmp
(
common
.
Big0
)
==
0
{
log
.
Info
(
"Proving withdrawal to OptimismPortal"
)
tx
,
err
:=
portal
.
ProveWithdrawalTransaction
(
opts
,
wdTx
,
l2OutputIndex
,
outputRootProof
,
trieNodes
,
)
if
err
!=
nil
{
return
err
}
receipt
,
err
:=
bind
.
WaitMined
(
context
.
Background
(),
l1Client
,
tx
)
if
err
!=
nil
{
return
err
}
if
receipt
.
Status
!=
types
.
ReceiptStatusSuccessful
{
return
errors
.
New
(
"withdrawal proof unsuccessful"
)
}
log
.
Info
(
"withdrawal proved"
,
"tx-hash"
,
tx
.
Hash
(),
"withdrawal-hash"
,
hash
)
block
,
err
:=
l1Client
.
BlockByHash
(
context
.
Background
(),
receipt
.
BlockHash
)
if
err
!=
nil
{
if
err
:=
proveWithdrawalTransaction
(
contracts
,
clients
,
opts
,
withdrawal
,
bedrockStartingBlockNumber
,
period
);
err
!=
nil
{
return
err
}
initialTime
:=
block
.
Time
()
for
{
log
.
Info
(
"waiting for finalization"
)
if
block
.
Time
()
>=
initialTime
+
period
.
Uint64
()
{
log
.
Info
(
"can be finalized"
)
break
}
time
.
Sleep
(
1
*
time
.
Second
)
block
,
err
=
l1Client
.
BlockByNumber
(
context
.
Background
(),
nil
)
if
err
!=
nil
{
return
err
}
}
}
else
{
log
.
Info
(
"Withdrawal already proven to OptimismPortal"
)
}
// check to see if the withdrawal has been finalized already
isFinalized
,
err
:=
p
ortal
.
FinalizedWithdrawals
(
&
bind
.
CallOpts
{},
hash
)
isFinalized
,
err
:=
contracts
.
OptimismP
ortal
.
FinalizedWithdrawals
(
&
bind
.
CallOpts
{},
hash
)
if
err
!=
nil
{
return
err
}
if
!
isFinalized
{
log
.
Info
(
"Finalizing withdrawal"
)
// Get the ETH balance of the withdrawal target *before* the finalization
targetBalBefore
,
err
:=
l1Client
.
BalanceAt
(
context
.
Background
(),
common
.
BytesToAddress
(
wd
.
Target
.
Bytes
())
,
nil
)
targetBalBefore
,
err
:=
clients
.
L1Client
.
BalanceAt
(
context
.
Background
(),
*
wd
.
Target
,
nil
)
if
err
!=
nil
{
return
err
}
log
.
Debug
(
"Balance before finalization"
,
"balance"
,
targetBalBefore
,
"account"
,
*
wd
.
Target
)
log
.
Debug
(
fmt
.
Sprintf
(
"Target balance before finalization: %v"
,
targetBalBefore
))
log
.
Info
(
"Finalizing withdrawal"
)
receipt
,
err
:=
finalizeWithdrawalTransaction
(
contracts
,
clients
,
opts
,
wd
,
withdrawal
)
log
.
Info
(
"withdrawal finalized"
,
"tx-hash"
,
receipt
.
TxHash
,
"withdrawal-hash"
,
hash
)
// Finalize withdrawal
tx
,
err
:=
portal
.
FinalizeWithdrawalTransaction
(
opts
,
wdTx
,
)
finalizationTrace
,
err
:=
callTrace
(
clients
,
receipt
)
if
err
!=
nil
{
return
err
return
nil
}
receipt
,
err
:=
bind
.
WaitMined
(
context
.
Background
(),
l1Client
,
tx
)
isSuccessNewPost
,
err
:=
contracts
.
L1CrossDomainMessenger
.
SuccessfulMessages
(
&
bind
.
CallOpts
{},
xdmHash
)
if
err
!=
nil
{
return
err
}
if
receipt
.
Status
!=
types
.
ReceiptStatusSuccessful
{
return
errors
.
New
(
"withdrawal finalize unsuccessful"
)
}
log
.
Info
(
"withdrawal finalized"
,
"tx-hash"
,
tx
.
Hash
(),
"withdrawal-hash"
,
hash
)
// fetch the call trace
var
finalizationTrace
callFrame
tracer
:=
"callTracer"
traceConfig
:=
tracers
.
TraceConfig
{
Tracer
:
&
tracer
,
}
err
=
l1RpcClient
.
Call
(
&
finalizationTrace
,
"debug_traceTransaction"
,
receipt
.
TxHash
,
traceConfig
)
if
err
!=
nil
{
return
err
// This would indicate that there is a replayability problem
if
isSuccess
&&
isSuccessNewPost
{
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"should revert"
);
err
!=
nil
{
return
err
}
panic
(
"THIS SHOULD REVERT"
)
}
callFrame
:=
findWithdrawalCall
(
&
finalizationTrace
,
wd
,
l1xdmAddr
)
if
callFrame
==
nil
{
return
errors
.
New
(
"cannot find callframe"
)
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"cannot find callframe"
);
err
!=
nil
{
return
err
}
continue
}
traceJson
,
err
:=
json
.
MarshalIndent
(
callFrame
,
""
,
" "
)
if
err
!=
nil
{
return
err
}
log
.
Info
(
fmt
.
Sprintf
(
"%v"
,
string
(
traceJson
)))
erc20Abi
,
err
:=
bindings
.
ERC20MetaData
.
GetAbi
()
if
err
!=
nil
{
return
err
}
transferEvent
:=
erc20Abi
.
Events
[
"Transfer"
]
log
.
Debug
(
fmt
.
Sprintf
(
"%v"
,
string
(
traceJson
)))
abi
,
err
:=
bindings
.
L1StandardBridgeMetaData
.
GetAbi
()
if
err
!=
nil
{
...
...
@@ -517,79 +439,13 @@ func main() {
switch
method
.
Name
{
case
"finalizeERC20Withdrawal"
:
// Handle logic for ERC20 withdrawals
l1Token
,
ok
:=
args
[
0
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
l2Token
,
ok
:=
args
[
1
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
from
,
ok
:=
args
[
2
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
to
,
ok
:=
args
[
3
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
amount
,
ok
:=
args
[
4
]
.
(
*
big
.
Int
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
extraData
,
ok
:=
args
[
5
]
.
([]
byte
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
log
.
Info
(
"decoded calldata"
,
"l1Token"
,
l1Token
,
"l2Token"
,
l2Token
,
"from"
,
from
,
"to"
,
to
,
"amount"
,
amount
,
"extraData"
,
extraData
,
)
// Look for the ERC20 token transfer topic
for
_
,
l
:=
range
receipt
.
Logs
{
topic
:=
l
.
Topics
[
0
]
if
topic
==
transferEvent
.
ID
{
a
,
_
:=
transferEvent
.
Inputs
.
Unpack
(
l
.
Data
)
// TODO: add a check here for balance diff
log
.
Info
(
"EVENT FOUND"
,
"args"
,
a
)
}
log
.
Info
(
"receipt topic"
,
"hex"
,
topic
.
Hex
())
if
err
:=
handleFinalizeERC20Withdrawal
(
args
,
receipt
,
l1StandardBridgeAddress
);
err
!=
nil
{
return
err
}
case
"finalizeETHWithdrawal"
:
// handle logic for ETH withdrawals
from
,
ok
:=
args
[
0
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: from"
)
if
err
:=
handleFinalizeETHWithdrawal
(
args
);
err
!=
nil
{
return
err
}
to
,
ok
:=
args
[
1
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: to"
)
}
amount
,
ok
:=
args
[
2
]
.
(
*
big
.
Int
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: amount"
)
}
extraData
,
ok
:=
args
[
3
]
.
([]
byte
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: extraData"
)
}
log
.
Info
(
"decoded calldata"
,
"from"
,
from
,
"to"
,
to
,
"amount"
,
amount
,
"extraData"
,
extraData
,
)
default
:
log
.
Info
(
"Unhandled method"
,
"name"
,
method
.
Name
)
}
...
...
@@ -604,55 +460,41 @@ func main() {
log
.
Info
(
"withdrawal action"
,
"function"
,
method
.
Name
,
"value"
,
wdValue
)
}
else
{
log
.
Info
(
"unknown method"
,
"to"
,
wd
.
Target
,
"data"
,
hexutil
.
Encode
(
wd
.
Data
))
badWithdrawals
=
append
(
badWithdrawals
,
badWithdrawal
{
Withdrawal
:
withdrawal
,
Legacy
:
wd
,
Trace
:
finalizationTrace
,
Index
:
i
,
})
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"unknown method"
);
err
!=
nil
{
return
err
}
}
// check that the user's intents are actually executed
if
common
.
HexToAddress
(
callFrame
.
To
)
!=
*
wd
.
Target
{
badWithdrawals
=
append
(
badWithdrawals
,
badWithdrawal
{
Withdrawal
:
withdrawal
,
Legacy
:
wd
,
Trace
:
finalizationTrace
,
Index
:
i
,
})
log
.
Info
(
"target mismatch"
,
"index"
,
i
)
continue
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"target mismatch"
);
err
!=
nil
{
return
err
}
panic
(
"target mismatch"
)
//continue
}
if
!
bytes
.
Equal
(
hexutil
.
MustDecode
(
callFrame
.
Input
),
wd
.
Data
)
{
badWithdrawals
=
append
(
badWithdrawals
,
badWithdrawal
{
Withdrawal
:
withdrawal
,
Legacy
:
wd
,
Trace
:
finalizationTrace
,
Index
:
i
,
})
log
.
Info
(
"calldata mismatch"
,
"index"
,
i
)
continue
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"calldata mismatch"
);
err
!=
nil
{
return
err
}
panic
(
"calldata mismatch"
)
//continue
}
if
callFrame
.
Value
!=
"0x"
+
wdValue
.
Text
(
16
)
{
badWithdrawals
=
append
(
badWithdrawals
,
badWithdrawal
{
Withdrawal
:
withdrawal
,
Legacy
:
wd
,
Trace
:
finalizationTrace
,
Index
:
i
,
})
if
callFrame
.
BigValue
()
.
Cmp
(
wdValue
)
!=
0
{
log
.
Info
(
"value mismatch"
,
"index"
,
i
)
continue
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"value mismatch"
);
err
!=
nil
{
return
err
}
panic
(
"value mismatch"
)
//continue
}
// Get the ETH balance of the withdrawal target *after* the finalization
targetBalAfter
,
err
:=
l
1Client
.
BalanceAt
(
context
.
Background
(),
*
wd
.
Target
,
nil
)
targetBalAfter
,
err
:=
clients
.
L
1Client
.
BalanceAt
(
context
.
Background
(),
*
wd
.
Target
,
nil
)
if
err
!=
nil
{
return
err
}
...
...
@@ -660,26 +502,23 @@ func main() {
diff
:=
new
(
big
.
Int
)
.
Sub
(
targetBalAfter
,
targetBalBefore
)
log
.
Debug
(
"balances"
,
"before"
,
targetBalBefore
,
"after"
,
targetBalAfter
,
"diff"
,
diff
)
if
diff
.
Cmp
(
wdValue
)
!=
0
{
badWithdrawals
=
append
(
badWithdrawals
,
badWithdrawal
{
Withdrawal
:
withdrawal
,
Legacy
:
wd
,
Trace
:
finalizationTrace
,
Index
:
i
,
})
log
.
Info
(
"native eth balance diff mismatch"
,
"index"
,
i
)
isSuccessNewPost
,
err
=
contracts
.
L1CrossDomainMessenger
.
SuccessfulMessages
(
&
bind
.
CallOpts
{},
xdmHash
)
if
err
!=
nil
{
return
err
}
continue
if
diff
.
Cmp
(
wdValue
)
!=
0
&&
isSuccessNewPost
&&
isSuccess
{
log
.
Info
(
"native eth balance diff mismatch"
,
"index"
,
i
,
"diff"
,
diff
,
"val"
,
wdValue
)
if
err
:=
writeSuspicious
(
f
,
withdrawal
,
wd
,
finalizationTrace
,
i
,
"balance mismatch"
);
err
!=
nil
{
return
err
}
panic
(
"balance mismatch"
)
//continue
}
}
else
{
log
.
Info
(
"Already finalized"
)
}
}
// Write the stuff to disk
if
err
:=
writeJSON
(
ctx
.
String
(
"bad-withdrawals-out"
),
badWithdrawals
);
err
!=
nil
{
return
err
}
return
nil
},
}
...
...
@@ -689,14 +528,415 @@ func main() {
}
}
func
writeJSON
(
outfile
string
,
input
interface
{})
error
{
f
,
err
:=
os
.
OpenFile
(
outfile
,
os
.
O_WRONLY
|
os
.
O_CREATE
|
os
.
O_TRUNC
,
0
o755
)
func
callTrace
(
c
*
clients
,
receipt
*
types
.
Receipt
)
(
callFrame
,
error
)
{
var
finalizationTrace
callFrame
tracer
:=
"callTracer"
traceConfig
:=
tracers
.
TraceConfig
{
Tracer
:
&
tracer
,
}
err
:=
c
.
L1RpcClient
.
Call
(
&
finalizationTrace
,
"debug_traceTransaction"
,
receipt
.
TxHash
,
traceConfig
)
if
err
!=
nil
{
return
finalizationTrace
,
err
}
return
finalizationTrace
,
err
}
func
handleFinalizeETHWithdrawal
(
args
[]
any
)
error
{
from
,
ok
:=
args
[
0
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: from"
)
}
to
,
ok
:=
args
[
1
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: to"
)
}
amount
,
ok
:=
args
[
2
]
.
(
*
big
.
Int
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: amount"
)
}
extraData
,
ok
:=
args
[
3
]
.
([]
byte
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid type: extraData"
)
}
log
.
Info
(
"decoded calldata"
,
"from"
,
from
,
"to"
,
to
,
"amount"
,
amount
,
"extraData"
,
extraData
,
)
return
nil
}
func
handleFinalizeERC20Withdrawal
(
args
[]
any
,
receipt
*
types
.
Receipt
,
l1StandardBridgeAddress
common
.
Address
)
error
{
erc20Abi
,
err
:=
bindings
.
ERC20MetaData
.
GetAbi
()
if
err
!=
nil
{
return
err
}
transferEvent
:=
erc20Abi
.
Events
[
"Transfer"
]
// Handle logic for ERC20 withdrawals
l1Token
,
ok
:=
args
[
0
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
l2Token
,
ok
:=
args
[
1
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
from
,
ok
:=
args
[
2
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
to
,
ok
:=
args
[
3
]
.
(
common
.
Address
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
amount
,
ok
:=
args
[
4
]
.
(
*
big
.
Int
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
extraData
,
ok
:=
args
[
5
]
.
([]
byte
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi"
)
}
log
.
Info
(
"decoded calldata"
,
"l1Token"
,
l1Token
,
"l2Token"
,
l2Token
,
"from"
,
from
,
"to"
,
to
,
"amount"
,
amount
,
"extraData"
,
extraData
,
)
// Look for the ERC20 token transfer topic
for
_
,
l
:=
range
receipt
.
Logs
{
topic
:=
l
.
Topics
[
0
]
if
topic
==
transferEvent
.
ID
{
if
l
.
Address
==
l1Token
{
a
,
_
:=
transferEvent
.
Inputs
.
Unpack
(
l
.
Data
)
if
len
(
l
.
Topics
)
<
3
{
return
fmt
.
Errorf
(
""
)
}
fmt
.
Printf
(
"%#v
\n
"
,
l
.
Topics
)
_from
:=
common
.
BytesToAddress
(
l
.
Topics
[
1
]
.
Bytes
())
_to
:=
common
.
BytesToAddress
(
l
.
Topics
[
2
]
.
Bytes
())
// from the L1StandardBridge
if
_from
!=
l1StandardBridgeAddress
{
return
fmt
.
Errorf
(
"from mismatch: %x - %x"
,
_from
,
l1StandardBridgeAddress
)
}
if
to
!=
_to
{
return
fmt
.
Errorf
(
"to mismatch: %x - %x"
,
to
,
_to
)
}
_amount
,
ok
:=
a
[
0
]
.
(
*
big
.
Int
)
if
!
ok
{
return
fmt
.
Errorf
(
"invalid abi in transfer event"
)
}
if
amount
.
Cmp
(
_amount
)
!=
0
{
return
fmt
.
Errorf
(
"amount mismatch: %d - %d"
,
amount
,
_amount
)
}
}
}
}
return
nil
}
func
proveWithdrawalTransaction
(
c
*
contracts
,
cl
*
clients
,
opts
*
bind
.
TransactOpts
,
withdrawal
*
crossdomain
.
Withdrawal
,
bn
,
finalizationPeriod
*
big
.
Int
)
error
{
l2OutputIndex
,
outputRootProof
,
trieNodes
,
err
:=
createOutput
(
withdrawal
,
c
.
L2OutputOracle
,
bn
,
cl
)
if
err
!=
nil
{
return
err
}
hash
,
err
:=
withdrawal
.
Hash
()
if
err
!=
nil
{
return
err
}
wdTx
:=
withdrawal
.
WithdrawalTransaction
()
tx
,
err
:=
c
.
OptimismPortal
.
ProveWithdrawalTransaction
(
opts
,
wdTx
,
l2OutputIndex
,
outputRootProof
,
trieNodes
,
)
if
err
!=
nil
{
return
err
}
receipt
,
err
:=
bind
.
WaitMined
(
context
.
Background
(),
cl
.
L1Client
,
tx
)
if
err
!=
nil
{
return
err
}
if
receipt
.
Status
!=
types
.
ReceiptStatusSuccessful
{
return
errors
.
New
(
"withdrawal proof unsuccessful"
)
}
log
.
Info
(
"withdrawal proved"
,
"tx-hash"
,
tx
.
Hash
(),
"withdrawal-hash"
,
hash
)
block
,
err
:=
cl
.
L1Client
.
BlockByHash
(
context
.
Background
(),
receipt
.
BlockHash
)
if
err
!=
nil
{
return
err
}
defer
f
.
Close
()
initialTime
:=
block
.
Time
()
for
{
log
.
Info
(
"waiting for finalization"
)
if
block
.
Time
()
>=
initialTime
+
finalizationPeriod
.
Uint64
()
{
log
.
Info
(
"can be finalized"
)
break
}
time
.
Sleep
(
1
*
time
.
Second
)
block
,
err
=
cl
.
L1Client
.
BlockByNumber
(
context
.
Background
(),
nil
)
if
err
!=
nil
{
return
err
}
}
return
nil
}
func
finalizeWithdrawalTransaction
(
c
*
contracts
,
cl
*
clients
,
opts
*
bind
.
TransactOpts
,
wd
*
crossdomain
.
LegacyWithdrawal
,
withdrawal
*
crossdomain
.
Withdrawal
,
)
(
*
types
.
Receipt
,
error
)
{
if
wd
.
Target
==
nil
{
return
nil
,
errors
.
New
(
"withdrawal target is nil, should never happen"
)
}
wdTx
:=
withdrawal
.
WithdrawalTransaction
()
// Finalize withdrawal
tx
,
err
:=
c
.
OptimismPortal
.
FinalizeWithdrawalTransaction
(
opts
,
wdTx
,
)
if
err
!=
nil
{
return
nil
,
err
}
receipt
,
err
:=
bind
.
WaitMined
(
context
.
Background
(),
cl
.
L1Client
,
tx
)
if
err
!=
nil
{
return
nil
,
err
}
if
receipt
.
Status
!=
types
.
ReceiptStatusSuccessful
{
return
nil
,
errors
.
New
(
"withdrawal finalize unsuccessful"
)
}
return
receipt
,
nil
}
// contracts represents a set of bound contracts
type
contracts
struct
{
OptimismPortal
*
bindings
.
OptimismPortal
L1CrossDomainMessenger
*
bindings
.
L1CrossDomainMessenger
L2OutputOracle
*
bindings
.
L2OutputOracle
}
// newContracts will create a contracts struct with the contract bindings
// preconfigured
func
newContracts
(
ctx
*
cli
.
Context
,
l1Backend
,
l2Backend
bind
.
ContractBackend
)
(
*
contracts
,
error
)
{
optimismPortalAddress
:=
ctx
.
String
(
"optimism-portal-address"
)
if
len
(
optimismPortalAddress
)
==
0
{
return
nil
,
errors
.
New
(
"OptimismPortal address not configured"
)
}
optimismPortalAddr
:=
common
.
HexToAddress
(
optimismPortalAddress
)
enc
:=
json
.
NewEncoder
(
f
)
enc
.
SetIndent
(
""
,
" "
)
return
enc
.
Encode
(
input
)
portal
,
err
:=
bindings
.
NewOptimismPortal
(
optimismPortalAddr
,
l1Backend
)
if
err
!=
nil
{
return
nil
,
err
}
l1xdmAddress
:=
ctx
.
String
(
"l1-crossdomain-messenger-address"
)
if
l1xdmAddress
==
""
{
return
nil
,
errors
.
New
(
"L1CrossDomainMessenger address not configured"
)
}
l1xdmAddr
:=
common
.
HexToAddress
(
l1xdmAddress
)
l1CrossDomainMessenger
,
err
:=
bindings
.
NewL1CrossDomainMessenger
(
l1xdmAddr
,
l1Backend
)
if
err
!=
nil
{
return
nil
,
err
}
l2OracleAddr
,
err
:=
portal
.
L2ORACLE
(
&
bind
.
CallOpts
{})
if
err
!=
nil
{
return
nil
,
err
}
oracle
,
err
:=
bindings
.
NewL2OutputOracle
(
l2OracleAddr
,
l1Backend
)
if
err
!=
nil
{
return
nil
,
err
}
log
.
Info
(
"Addresses"
,
"l1-crossdomain-messenger"
,
l1xdmAddr
,
"optimism-portal"
,
optimismPortalAddr
,
"l2-output-oracle"
,
l2OracleAddr
,
)
return
&
contracts
{
OptimismPortal
:
portal
,
L1CrossDomainMessenger
:
l1CrossDomainMessenger
,
L2OutputOracle
:
oracle
,
},
nil
}
// clients represents a set of initialized RPC clients
type
clients
struct
{
L1Client
*
ethclient
.
Client
L2Client
*
ethclient
.
Client
L1RpcClient
*
rpc
.
Client
L2RpcClient
*
rpc
.
Client
L1GethClient
*
gethclient
.
Client
L2GethClient
*
gethclient
.
Client
}
// newClients will create new RPC clients
func
newClients
(
ctx
*
cli
.
Context
)
(
*
clients
,
error
)
{
l1RpcURL
:=
ctx
.
String
(
"l1-rpc-url"
)
l1Client
,
err
:=
ethclient
.
Dial
(
l1RpcURL
)
if
err
!=
nil
{
return
nil
,
err
}
l1ChainID
,
err
:=
l1Client
.
ChainID
(
context
.
Background
())
if
err
!=
nil
{
return
nil
,
err
}
l2RpcURL
:=
ctx
.
String
(
"l2-rpc-url"
)
l2Client
,
err
:=
ethclient
.
Dial
(
l2RpcURL
)
if
err
!=
nil
{
return
nil
,
err
}
l2ChainID
,
err
:=
l2Client
.
ChainID
(
context
.
Background
())
if
err
!=
nil
{
return
nil
,
err
}
l1RpcClient
,
err
:=
rpc
.
DialContext
(
context
.
Background
(),
l1RpcURL
)
if
err
!=
nil
{
return
nil
,
err
}
l2RpcClient
,
err
:=
rpc
.
DialContext
(
context
.
Background
(),
l2RpcURL
)
if
err
!=
nil
{
return
nil
,
err
}
l1GethClient
:=
gethclient
.
New
(
l1RpcClient
)
l2GethClient
:=
gethclient
.
New
(
l2RpcClient
)
log
.
Info
(
"Set up RPC clients"
,
"l1-chain-id"
,
l1ChainID
,
"l2-chain-id"
,
l2ChainID
,
)
return
&
clients
{
L1Client
:
l1Client
,
L2Client
:
l2Client
,
L1RpcClient
:
l1RpcClient
,
L2RpcClient
:
l2RpcClient
,
L1GethClient
:
l1GethClient
,
L2GethClient
:
l2GethClient
,
},
nil
}
// newWithdrawals will create a set of legacy withdrawals
func
newWithdrawals
(
ctx
*
cli
.
Context
,
l1ChainID
*
big
.
Int
)
([]
*
crossdomain
.
LegacyWithdrawal
,
error
)
{
ovmMsgs
:=
ctx
.
String
(
"ovm-messages"
)
evmMsgs
:=
ctx
.
String
(
"evm-messages"
)
log
.
Debug
(
"Migration data"
,
"ovm-path"
,
ovmMsgs
,
"evm-messages"
,
evmMsgs
)
ovmMessages
,
err
:=
migration
.
NewSentMessage
(
ovmMsgs
)
if
err
!=
nil
{
return
nil
,
err
}
// use empty ovmMessages if its not mainnet
if
l1ChainID
.
Cmp
(
common
.
Big1
)
!=
0
{
log
.
Info
(
"not using ovm messages because its not mainnet"
)
ovmMessages
=
[]
*
migration
.
SentMessage
{}
}
evmMessages
,
err
:=
migration
.
NewSentMessage
(
evmMsgs
)
if
err
!=
nil
{
return
nil
,
err
}
migrationData
:=
migration
.
MigrationData
{
OvmMessages
:
ovmMessages
,
EvmMessages
:
evmMessages
,
}
wds
,
err
:=
migrationData
.
ToWithdrawals
()
if
err
!=
nil
{
return
nil
,
err
}
if
len
(
wds
)
==
0
{
return
nil
,
errors
.
New
(
"no withdrawals"
)
}
log
.
Info
(
"Converted migration data to withdrawals successfully"
,
"count"
,
len
(
wds
))
return
wds
,
nil
}
// newTransactor creates a new transact context given a cli context
func
newTransactor
(
ctx
*
cli
.
Context
)
(
*
bind
.
TransactOpts
,
error
)
{
if
ctx
.
String
(
"private-key"
)
==
""
{
return
nil
,
errors
.
New
(
"No private key to transact with"
)
}
privateKey
,
err
:=
crypto
.
HexToECDSA
(
strings
.
TrimPrefix
(
ctx
.
String
(
"private-key"
),
"0x"
))
if
err
!=
nil
{
return
nil
,
err
}
l1RpcURL
:=
ctx
.
String
(
"l1-rpc-url"
)
l1Client
,
err
:=
ethclient
.
Dial
(
l1RpcURL
)
if
err
!=
nil
{
return
nil
,
err
}
l1ChainID
,
err
:=
l1Client
.
ChainID
(
context
.
Background
())
if
err
!=
nil
{
return
nil
,
err
}
opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
privateKey
,
l1ChainID
)
if
err
!=
nil
{
return
nil
,
err
}
return
opts
,
nil
}
func
writeSuspicious
(
f
*
os
.
File
,
withdrawal
*
crossdomain
.
Withdrawal
,
wd
*
crossdomain
.
LegacyWithdrawal
,
finalizationTrace
callFrame
,
i
int
,
reason
string
,
)
error
{
bad
:=
suspiciousWithdrawal
{
Withdrawal
:
withdrawal
,
Legacy
:
wd
,
Trace
:
finalizationTrace
,
Index
:
i
,
Reason
:
reason
,
}
data
,
err
:=
json
.
Marshal
(
bad
)
if
err
!=
nil
{
return
err
}
_
,
err
=
f
.
WriteString
(
string
(
data
)
+
"
\n
"
)
return
err
}
op-chain-ops/crossdomain/legacy_withdrawal.go
View file @
b2242f40
...
...
@@ -10,6 +10,7 @@ import (
"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/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
...
...
@@ -17,7 +18,7 @@ import (
type
LegacyWithdrawal
struct
{
Target
*
common
.
Address
`json:"target"`
Sender
*
common
.
Address
`json:"sender"`
Data
[]
byte
`json:"data"`
Data
hexutil
.
Bytes
`json:"data"`
Nonce
*
big
.
Int
`json:"nonce"`
}
...
...
@@ -38,7 +39,7 @@ func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big
// through the standard optimism cross domain messaging system by hashing in
// the L2CrossDomainMessenger address.
func
(
w
*
LegacyWithdrawal
)
Encode
()
([]
byte
,
error
)
{
enc
,
err
:=
EncodeCrossDomainMessageV0
(
w
.
Target
,
w
.
Sender
,
w
.
Data
,
w
.
Nonce
)
enc
,
err
:=
EncodeCrossDomainMessageV0
(
w
.
Target
,
w
.
Sender
,
[]
byte
(
w
.
Data
)
,
w
.
Nonce
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot encode LegacyWithdrawal: %w"
,
err
)
}
...
...
@@ -98,7 +99,7 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
w
.
Target
=
&
target
w
.
Sender
=
&
sender
w
.
Data
=
msgData
w
.
Data
=
hexutil
.
Bytes
(
msgData
)
w
.
Nonce
=
nonce
return
nil
}
...
...
op-chain-ops/crossdomain/message.go
View file @
b2242f40
...
...
@@ -72,6 +72,12 @@ func (c *CrossDomainMessage) Hash() (common.Hash, error) {
}
}
// HashV1 forces using the V1 hash even if its a legacy hash. This is used
// for the migration process.
func
(
c
*
CrossDomainMessage
)
HashV1
()
(
common
.
Hash
,
error
)
{
return
HashCrossDomainMessageV1
(
c
.
Nonce
,
c
.
Sender
,
c
.
Target
,
c
.
Value
,
c
.
GasLimit
,
c
.
Data
)
}
// ToWithdrawal will turn a CrossDomainMessage into a Withdrawal.
// This only works for version 0 CrossDomainMessages as not all of
// the data is present for version 1 CrossDomainMessages to be turned
...
...
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