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
2cf845a9
Commit
2cf845a9
authored
Nov 14, 2023
by
Hamdi Allam
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pre-bedrock withdrawals with a bedrock tx withdrawal hash
parent
2e35a8f6
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
198 additions
and
88 deletions
+198
-88
bridge_messages.go
indexer/database/bridge_messages.go
+37
-1
cross_domain_messages.go
indexer/e2e_tests/utils/cross_domain_messages.go
+12
-17
20230523_create_schema.sql
indexer/migrations/20230523_create_schema.sql
+16
-0
bridge.go
indexer/processors/bridge.go
+1
-1
legacy_bridge_processor.go
indexer/processors/bridge/legacy_bridge_processor.go
+52
-11
legacy_bridge_processor_test.go
indexer/processors/bridge/legacy_bridge_processor_test.go
+49
-0
cross_domain_messenger.go
indexer/processors/contracts/cross_domain_messenger.go
+31
-38
utils.go
indexer/processors/contracts/utils.go
+0
-20
No files found.
indexer/database/bridge_messages.go
View file @
2cf845a9
...
@@ -39,6 +39,11 @@ type L2BridgeMessage struct {
...
@@ -39,6 +39,11 @@ type L2BridgeMessage struct {
TransactionWithdrawalHash
common
.
Hash
`gorm:"serializer:bytes"`
TransactionWithdrawalHash
common
.
Hash
`gorm:"serializer:bytes"`
}
}
type
versionedMessageHash
struct
{
MessageHash
common
.
Hash
`gorm:"primaryKey;serializer:bytes"`
V1MessageHash
common
.
Hash
`gorm:"serializer:bytes"`
}
type
BridgeMessagesView
interface
{
type
BridgeMessagesView
interface
{
L1BridgeMessage
(
common
.
Hash
)
(
*
L1BridgeMessage
,
error
)
L1BridgeMessage
(
common
.
Hash
)
(
*
L1BridgeMessage
,
error
)
L1BridgeMessageWithFilter
(
BridgeMessage
)
(
*
L1BridgeMessage
,
error
)
L1BridgeMessageWithFilter
(
BridgeMessage
)
(
*
L1BridgeMessage
,
error
)
...
@@ -55,6 +60,8 @@ type BridgeMessagesDB interface {
...
@@ -55,6 +60,8 @@ type BridgeMessagesDB interface {
StoreL2BridgeMessages
([]
L2BridgeMessage
)
error
StoreL2BridgeMessages
([]
L2BridgeMessage
)
error
MarkRelayedL2BridgeMessage
(
common
.
Hash
,
uuid
.
UUID
)
error
MarkRelayedL2BridgeMessage
(
common
.
Hash
,
uuid
.
UUID
)
error
StoreL2BridgeMessageV1MessageHash
(
common
.
Hash
,
common
.
Hash
)
error
}
}
/**
/**
...
@@ -134,8 +141,37 @@ func (db bridgeMessagesDB) StoreL2BridgeMessages(messages []L2BridgeMessage) err
...
@@ -134,8 +141,37 @@ func (db bridgeMessagesDB) StoreL2BridgeMessages(messages []L2BridgeMessage) err
return
result
.
Error
return
result
.
Error
}
}
func
(
db
bridgeMessagesDB
)
StoreL2BridgeMessageV1MessageHash
(
msgHash
,
v1MsgHash
common
.
Hash
)
error
{
if
msgHash
==
v1MsgHash
{
return
fmt
.
Errorf
(
"message hash is equal to the v1 message: %s"
,
msgHash
)
}
deduped
:=
db
.
gorm
.
Clauses
(
clause
.
OnConflict
{
Columns
:
[]
clause
.
Column
{{
Name
:
"message_hash"
}},
DoNothing
:
true
})
result
:=
deduped
.
Create
(
&
versionedMessageHash
{
MessageHash
:
msgHash
,
V1MessageHash
:
v1MsgHash
})
if
result
.
Error
==
nil
&&
int
(
result
.
RowsAffected
)
<
1
{
db
.
log
.
Warn
(
"ignored L2 bridge v1 message hash duplicates"
)
}
return
result
.
Error
}
func
(
db
bridgeMessagesDB
)
L2BridgeMessage
(
msgHash
common
.
Hash
)
(
*
L2BridgeMessage
,
error
)
{
func
(
db
bridgeMessagesDB
)
L2BridgeMessage
(
msgHash
common
.
Hash
)
(
*
L2BridgeMessage
,
error
)
{
return
db
.
L2BridgeMessageWithFilter
(
BridgeMessage
{
MessageHash
:
msgHash
})
message
,
err
:=
db
.
L2BridgeMessageWithFilter
(
BridgeMessage
{
MessageHash
:
msgHash
})
if
message
!=
nil
||
err
!=
nil
{
return
message
,
err
}
// check if this is a v1 hash of an older message
versioned
:=
versionedMessageHash
{
V1MessageHash
:
msgHash
}
result
:=
db
.
gorm
.
Where
(
&
versioned
)
.
Take
(
&
versioned
)
if
result
.
Error
!=
nil
{
if
errors
.
Is
(
result
.
Error
,
gorm
.
ErrRecordNotFound
)
{
return
nil
,
nil
}
return
nil
,
result
.
Error
}
return
db
.
L2BridgeMessageWithFilter
(
BridgeMessage
{
MessageHash
:
versioned
.
MessageHash
})
}
}
func
(
db
bridgeMessagesDB
)
L2BridgeMessageWithFilter
(
filter
BridgeMessage
)
(
*
L2BridgeMessage
,
error
)
{
func
(
db
bridgeMessagesDB
)
L2BridgeMessageWithFilter
(
filter
BridgeMessage
)
(
*
L2BridgeMessage
,
error
)
{
...
...
indexer/e2e_tests/utils/cross_domain_messages.go
View file @
2cf845a9
...
@@ -4,12 +4,11 @@ import (
...
@@ -4,12 +4,11 @@ import (
"errors"
"errors"
"math/big"
"math/big"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
)
)
type
CrossDomainMessengerSentMessage
struct
{
type
CrossDomainMessengerSentMessage
struct
{
...
@@ -40,7 +39,17 @@ func ParseCrossDomainMessage(sentMessageReceipt *types.Receipt) (CrossDomainMess
...
@@ -40,7 +39,17 @@ func ParseCrossDomainMessage(sentMessageReceipt *types.Receipt) (CrossDomainMess
if
err
!=
nil
{
if
err
!=
nil
{
return
CrossDomainMessengerSentMessage
{},
err
return
CrossDomainMessengerSentMessage
{},
err
}
}
msgHash
,
err
:=
CrossDomainMessengerSentMessageHash
(
sentMessage
,
sentMessageExtension
.
Value
)
msg
:=
crossdomain
.
NewCrossDomainMessage
(
sentMessage
.
MessageNonce
,
sentMessage
.
Sender
,
sentMessage
.
Target
,
sentMessageExtension
.
Value
,
sentMessage
.
GasLimit
,
sentMessage
.
Message
,
)
msgHash
,
err
:=
msg
.
Hash
()
if
err
!=
nil
{
if
err
!=
nil
{
return
CrossDomainMessengerSentMessage
{},
err
return
CrossDomainMessengerSentMessage
{},
err
}
}
...
@@ -51,17 +60,3 @@ func ParseCrossDomainMessage(sentMessageReceipt *types.Receipt) (CrossDomainMess
...
@@ -51,17 +60,3 @@ func ParseCrossDomainMessage(sentMessageReceipt *types.Receipt) (CrossDomainMess
return
CrossDomainMessengerSentMessage
{},
errors
.
New
(
"missing SentMessage receipts"
)
return
CrossDomainMessengerSentMessage
{},
errors
.
New
(
"missing SentMessage receipts"
)
}
}
func
CrossDomainMessengerSentMessageHash
(
sentMessage
*
bindings
.
CrossDomainMessengerSentMessage
,
value
*
big
.
Int
)
(
common
.
Hash
,
error
)
{
abi
,
err
:=
bindings
.
CrossDomainMessengerMetaData
.
GetAbi
()
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
calldata
,
err
:=
contracts
.
CrossDomainMessageCalldata
(
abi
,
sentMessage
,
value
)
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
return
crypto
.
Keccak256Hash
(
calldata
),
nil
}
indexer/migrations/20230523_create_schema.sql
View file @
2cf845a9
...
@@ -176,6 +176,22 @@ CREATE INDEX IF NOT EXISTS l2_bridge_messages_timestamp ON l2_bridge_messages(ti
...
@@ -176,6 +176,22 @@ CREATE INDEX IF NOT EXISTS l2_bridge_messages_timestamp ON l2_bridge_messages(ti
CREATE
INDEX
IF
NOT
EXISTS
l2_bridge_messages_transaction_withdrawal_hash
ON
l2_bridge_messages
(
transaction_withdrawal_hash
);
CREATE
INDEX
IF
NOT
EXISTS
l2_bridge_messages_transaction_withdrawal_hash
ON
l2_bridge_messages
(
transaction_withdrawal_hash
);
CREATE
INDEX
IF
NOT
EXISTS
l2_bridge_messages_from_address
ON
l2_bridge_messages
(
from_address
);
CREATE
INDEX
IF
NOT
EXISTS
l2_bridge_messages_from_address
ON
l2_bridge_messages
(
from_address
);
/**
* Since the CDM uses the latest versioned message hash when emitting the `RelayedMessage` event, we need
* to keep track of all of the future versions of message hashes such that legacy messages can be queried
* queried for when relayed on L1
*
* As new the CDM is updated with new versions, we need to ensure that there's a better way to correlate message between
* chains (adding the message nonce to the RelayedMessage event) or continue to add columns to this table and migrate
* unrelayed messages such that finalization logic can handle switching between the varying versioned message hashes
*/
CREATE
TABLE
IF
NOT
EXISTS
l2_bridge_messages_versioned_message_hashes
(
message_hash
VARCHAR
PRIMARY
KEY
NOT
NULL
UNIQUE
REFERENCES
l2_bridge_messages
(
message_hash
),
-- only filled in if `message_hash` is for a v0 message
v1_message_hash
VARCHAR
UNIQUE
);
-- StandardBridge
-- StandardBridge
CREATE
TABLE
IF
NOT
EXISTS
l1_bridge_deposits
(
CREATE
TABLE
IF
NOT
EXISTS
l1_bridge_deposits
(
transaction_source_hash
VARCHAR
PRIMARY
KEY
REFERENCES
l1_transaction_deposits
(
source_hash
)
ON
DELETE
CASCADE
,
transaction_source_hash
VARCHAR
PRIMARY
KEY
REFERENCES
l1_transaction_deposits
(
source_hash
)
ON
DELETE
CASCADE
,
...
...
indexer/processors/bridge.go
View file @
2cf845a9
...
@@ -256,7 +256,7 @@ func (b *BridgeProcessor) processInitiatedL2Events() error {
...
@@ -256,7 +256,7 @@ func (b *BridgeProcessor) processInitiatedL2Events() error {
legacyBridgeLog
:=
l2BridgeLog
.
New
(
"mode"
,
"legacy"
,
"from_block_number"
,
legacyFromL2Height
,
"to_block_number"
,
legacyToL2Height
)
legacyBridgeLog
:=
l2BridgeLog
.
New
(
"mode"
,
"legacy"
,
"from_block_number"
,
legacyFromL2Height
,
"to_block_number"
,
legacyToL2Height
)
legacyBridgeLog
.
Info
(
"scanning for initiated bridge events"
)
legacyBridgeLog
.
Info
(
"scanning for initiated bridge events"
)
if
err
:=
bridge
.
LegacyL2ProcessInitiatedBridgeEvents
(
legacyBridgeLog
,
tx
,
b
.
metrics
,
b
.
chainConfig
.
L2Contracts
,
legacyFromL2Height
,
legacyToL2Height
);
err
!=
nil
{
if
err
:=
bridge
.
LegacyL2ProcessInitiatedBridgeEvents
(
legacyBridgeLog
,
tx
,
b
.
metrics
,
b
.
chainConfig
.
Preset
,
b
.
chainConfig
.
L2Contracts
,
legacyFromL2Height
,
legacyToL2Height
);
err
!=
nil
{
return
err
return
err
}
else
if
legacyToL2Height
.
Cmp
(
toL2Height
)
==
0
{
}
else
if
legacyToL2Height
.
Cmp
(
toL2Height
)
==
0
{
return
nil
// a-ok! Entire range was legacy blocks
return
nil
// a-ok! Entire range was legacy blocks
...
...
indexer/processors/bridge/legacy_bridge_processor.go
View file @
2cf845a9
...
@@ -12,6 +12,8 @@ import (
...
@@ -12,6 +12,8 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
)
)
// Legacy Bridge Initiation
// Legacy Bridge Initiation
...
@@ -145,7 +147,7 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metri
...
@@ -145,7 +147,7 @@ func LegacyL1ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metri
// 1. L2CrossDomainMessenger - The LegacyMessagePasser contract cannot be used as entrypoint to bridge transactions from L2. The protocol
// 1. L2CrossDomainMessenger - The LegacyMessagePasser contract cannot be used as entrypoint to bridge transactions from L2. The protocol
// only allows the L2CrossDomainMessenger as the sole sender when relaying a bridged message.
// only allows the L2CrossDomainMessenger as the sole sender when relaying a bridged message.
// 2. L2StandardBridge
// 2. L2StandardBridge
func
LegacyL2ProcessInitiatedBridgeEvents
(
log
log
.
Logger
,
db
*
database
.
DB
,
metrics
L2Metricer
,
l2Contracts
config
.
L2Contracts
,
fromHeight
,
toHeight
*
big
.
Int
)
error
{
func
LegacyL2ProcessInitiatedBridgeEvents
(
log
log
.
Logger
,
db
*
database
.
DB
,
metrics
L2Metricer
,
preset
int
,
l2Contracts
config
.
L2Contracts
,
fromHeight
,
toHeight
*
big
.
Int
)
error
{
// (1) L2CrossDomainMessenger
// (1) L2CrossDomainMessenger
crossDomainSentMessages
,
err
:=
contracts
.
CrossDomainMessengerSentMessageEvents
(
"l2"
,
l2Contracts
.
L2CrossDomainMessenger
,
db
,
fromHeight
,
toHeight
)
crossDomainSentMessages
,
err
:=
contracts
.
CrossDomainMessengerSentMessageEvents
(
"l2"
,
l2Contracts
.
L2CrossDomainMessenger
,
db
,
fromHeight
,
toHeight
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -168,22 +170,36 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metri
...
@@ -168,22 +170,36 @@ func LegacyL2ProcessInitiatedBridgeEvents(log log.Logger, db *database.DB, metri
sentMessage
:=
crossDomainSentMessages
[
i
]
sentMessage
:=
crossDomainSentMessages
[
i
]
withdrawnWEI
=
new
(
big
.
Int
)
.
Add
(
withdrawnWEI
,
sentMessage
.
BridgeMessage
.
Tx
.
Amount
)
withdrawnWEI
=
new
(
big
.
Int
)
.
Add
(
withdrawnWEI
,
sentMessage
.
BridgeMessage
.
Tx
.
Amount
)
// We re-use the L2CrossDomainMessenger message hash as the withdrawal hash to remain consistent in the schema.
// Since these message can be relayed in bedrock, we utilize the migrated withdrawal hash
// and also store the v1 version of the message hash such that the bedrock l1 finalization
// processor works as expected
v1MessageHash
,
err
:=
legacyBridgeMessageV1MessageHash
(
&
sentMessage
.
BridgeMessage
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to compute versioned message hash: %w"
,
err
)
}
db
.
BridgeMessages
.
StoreL2BridgeMessageV1MessageHash
(
sentMessage
.
BridgeMessage
.
MessageHash
,
v1MessageHash
)
withdrawalHash
,
err
:=
legacyBridgeMessageWithdrawalHash
(
preset
,
&
sentMessage
.
BridgeMessage
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to construct migrated withdrawal hash: %w"
,
err
)
}
transactionWithdrawals
[
i
]
=
database
.
L2TransactionWithdrawal
{
transactionWithdrawals
[
i
]
=
database
.
L2TransactionWithdrawal
{
WithdrawalHash
:
sentMessage
.
BridgeMessage
.
Message
Hash
,
WithdrawalHash
:
withdrawal
Hash
,
InitiatedL2EventGUID
:
sentMessage
.
Event
.
GUID
,
InitiatedL2EventGUID
:
sentMessage
.
Event
.
GUID
,
Nonce
:
sentMessage
.
BridgeMessage
.
Nonce
,
Nonce
:
sentMessage
.
BridgeMessage
.
Nonce
,
GasLimit
:
sentMessage
.
BridgeMessage
.
GasLimit
,
GasLimit
:
sentMessage
.
BridgeMessage
.
GasLimit
,
Tx
:
database
.
Transaction
{
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
BridgeMessage
.
Tx
.
FromAddress
,
FromAddress
:
sentMessage
.
BridgeMessage
.
Tx
.
FromAddress
,
ToAddress
:
sentMessage
.
BridgeMessage
.
Tx
.
ToAddress
,
ToAddress
:
sentMessage
.
BridgeMessage
.
Tx
.
ToAddress
,
Amount
:
big
.
NewInt
(
0
)
,
Amount
:
big
int
.
Zero
,
Data
:
sentMessage
.
BridgeMessage
.
Tx
.
Data
,
Data
:
sentMessage
.
BridgeMessage
.
Tx
.
Data
,
Timestamp
:
sentMessage
.
Event
.
Timestamp
,
Timestamp
:
sentMessage
.
Event
.
Timestamp
,
},
},
}
}
sentMessages
[
logKey
{
sentMessage
.
Event
.
BlockHash
,
sentMessage
.
Event
.
LogIndex
}]
=
sentMessageEvent
{
&
sentMessage
,
sentMessage
.
BridgeMessage
.
Message
Hash
}
sentMessages
[
logKey
{
sentMessage
.
Event
.
BlockHash
,
sentMessage
.
Event
.
LogIndex
}]
=
sentMessageEvent
{
&
sentMessage
,
withdrawal
Hash
}
bridgeMessages
[
i
]
=
database
.
L2BridgeMessage
{
bridgeMessages
[
i
]
=
database
.
L2BridgeMessage
{
TransactionWithdrawalHash
:
sentMessage
.
BridgeMessage
.
MessageHash
,
TransactionWithdrawalHash
:
sentMessage
.
BridgeMessage
.
MessageHash
,
BridgeMessage
:
sentMessage
.
BridgeMessage
,
BridgeMessage
:
sentMessage
.
BridgeMessage
,
...
@@ -297,16 +313,17 @@ func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metri
...
@@ -297,16 +313,17 @@ func LegacyL1ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metri
}
}
}
}
// Mark the associated tx withdrawal as proven/finalized with the same event. The message hash is also the transaction withdrawal hash
if
err
:=
db
.
BridgeMessages
.
MarkRelayedL2BridgeMessage
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
if
err
:=
db
.
BridgeTransactions
.
MarkL2TransactionWithdrawalProvenEvent
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to relay cross domain message. tx_hash = %s: %w"
,
relayedMessage
.
Event
.
TransactionHash
,
err
)
}
// Mark the associated tx withdrawal as proven/finalized with the same event.
if
err
:=
db
.
BridgeTransactions
.
MarkL2TransactionWithdrawalProvenEvent
(
message
.
TransactionWithdrawalHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to mark withdrawal as proven. tx_hash = %s: %w"
,
relayedMessage
.
Event
.
TransactionHash
,
err
)
return
fmt
.
Errorf
(
"failed to mark withdrawal as proven. tx_hash = %s: %w"
,
relayedMessage
.
Event
.
TransactionHash
,
err
)
}
}
if
err
:=
db
.
BridgeTransactions
.
MarkL2TransactionWithdrawalFinalizedEvent
(
relayedMessage
.
Message
Hash
,
relayedMessage
.
Event
.
GUID
,
true
);
err
!=
nil
{
if
err
:=
db
.
BridgeTransactions
.
MarkL2TransactionWithdrawalFinalizedEvent
(
message
.
TransactionWithdrawal
Hash
,
relayedMessage
.
Event
.
GUID
,
true
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to mark withdrawal as finalized. tx_hash = %s: %w"
,
relayedMessage
.
Event
.
TransactionHash
,
err
)
return
fmt
.
Errorf
(
"failed to mark withdrawal as finalized. tx_hash = %s: %w"
,
relayedMessage
.
Event
.
TransactionHash
,
err
)
}
}
if
err
:=
db
.
BridgeMessages
.
MarkRelayedL2BridgeMessage
(
relayedMessage
.
MessageHash
,
relayedMessage
.
Event
.
GUID
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to relay cross domain message. tx_hash = %s: %w"
,
relayedMessage
.
Event
.
TransactionHash
,
err
)
}
}
}
if
len
(
crossDomainRelayedMessages
)
>
0
{
if
len
(
crossDomainRelayedMessages
)
>
0
{
metrics
.
RecordL1ProvenWithdrawals
(
len
(
crossDomainRelayedMessages
))
metrics
.
RecordL1ProvenWithdrawals
(
len
(
crossDomainRelayedMessages
))
...
@@ -370,3 +387,27 @@ func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metri
...
@@ -370,3 +387,27 @@ func LegacyL2ProcessFinalizedBridgeEvents(log log.Logger, db *database.DB, metri
// a-ok!
// a-ok!
return
nil
return
nil
}
}
// Utils
func
legacyBridgeMessageWithdrawalHash
(
preset
int
,
msg
*
database
.
BridgeMessage
)
(
common
.
Hash
,
error
)
{
l1Cdm
:=
config
.
Presets
[
preset
]
.
ChainConfig
.
L1Contracts
.
L1CrossDomainMessengerProxy
legacyWithdrawal
:=
crossdomain
.
NewLegacyWithdrawal
(
predeploys
.
L2CrossDomainMessengerAddr
,
msg
.
Tx
.
ToAddress
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
Data
,
msg
.
Nonce
)
migratedWithdrawal
,
err
:=
crossdomain
.
MigrateWithdrawal
(
legacyWithdrawal
,
&
l1Cdm
,
big
.
NewInt
(
int64
(
preset
)))
if
err
!=
nil
{
return
common
.
Hash
{},
err
}
return
migratedWithdrawal
.
Hash
()
}
func
legacyBridgeMessageV1MessageHash
(
msg
*
database
.
BridgeMessage
)
(
common
.
Hash
,
error
)
{
legacyWithdrawal
:=
crossdomain
.
NewLegacyWithdrawal
(
predeploys
.
L2CrossDomainMessengerAddr
,
msg
.
Tx
.
ToAddress
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
Data
,
msg
.
Nonce
)
value
,
err
:=
legacyWithdrawal
.
Value
()
if
err
!=
nil
{
return
common
.
Hash
{},
fmt
.
Errorf
(
"failed to extract ETH value from legacy bridge message: %w"
,
err
)
}
// Note: GasLimit is always zero. Only the GasLimit for the withdrawal transaction was migrated
return
crossdomain
.
HashCrossDomainMessageV1
(
msg
.
Nonce
,
msg
.
Tx
.
FromAddress
,
msg
.
Tx
.
ToAddress
,
value
,
new
(
big
.
Int
),
msg
.
Tx
.
Data
)
}
indexer/processors/bridge/legacy_bridge_processor_test.go
0 → 100644
View file @
2cf845a9
package
bridge
import
(
"testing"
"github.com/ethereum-optimism/optimism/indexer/bigint"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/processors/contracts"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)
func
TestLegacyWithdrawalAndMessageHash
(
t
*
testing
.
T
)
{
// Pre-Bedrock OP-Goerli withdrawal that was proven post-bedrock
// - L1 proven withdrawal tx: 0xa8853a3532f40052385602c66512e438bc1e3736d3cb7abde359f5b9377441c7
value
:=
bigint
.
Zero
expectedWithdrawalHash
:=
common
.
HexToHash
(
"0xae99d25df3e38730f6ee6588733417e20a131923b84870be6aedb4f863b6302d"
)
// Ensure the L2 Tx which correlates with the above proven withdrawal results in the same computed withdrawal hash
// - L2 withdrawal tx: 0x254d9c28add020404142f840ed794cea51f86c0f0a737e3e7bdd7e1e4550962e
abi
,
err
:=
bindings
.
CrossDomainMessengerMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
var
sentMessage
bindings
.
CrossDomainMessengerSentMessage
sentMessageEvent
:=
abi
.
Events
[
"SentMessage"
]
logData
:=
common
.
FromHex
(
"0x0000000000000000000000004200000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000186a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a9f9e67500000000000000000000000007865c6e87b9f70255377e024ace6630c1eaa37f0000000000000000000000003b8e53b3ab8e01fb57d0c9e893bc4d655aa67d84000000000000000000000000b91882244f7f82540f2941a759724523c7b9a166000000000000000000000000b91882244f7f82540f2941a759724523c7b9a166000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
)
require
.
NoError
(
t
,
contracts
.
UnpackLog
(
&
sentMessage
,
&
types
.
Log
{
Data
:
logData
,
Topics
:
[]
common
.
Hash
{
sentMessageEvent
.
ID
,
common
.
HexToHash
(
"0x000000000000000000000000636af16bf2f682dd3109e60102b8e1a089fedaa8"
)}},
sentMessageEvent
.
Name
,
abi
))
// timestamp and message hash are filled in fields. not core to the event
msg
:=
database
.
BridgeMessage
{
Nonce
:
sentMessage
.
MessageNonce
,
GasLimit
:
sentMessage
.
GasLimit
,
Tx
:
database
.
Transaction
{
FromAddress
:
sentMessage
.
Sender
,
ToAddress
:
sentMessage
.
Target
,
Amount
:
value
,
Data
:
sentMessage
.
Message
},
}
hash
,
err
:=
legacyBridgeMessageWithdrawalHash
(
420
,
&
msg
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedWithdrawalHash
,
hash
)
// Ensure the relayed message hash (v1) matches
expectedMessageHash
:=
common
.
HexToHash
(
"0xcb16ecc1967f5d7aed909349a4351d28fbb396429ef7faf1c9d2a670e3ca906f"
)
v1MessageHash
,
err
:=
legacyBridgeMessageV1MessageHash
(
&
msg
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
expectedMessageHash
,
v1MessageHash
)
}
indexer/processors/contracts/cross_domain_messenger.go
View file @
2cf845a9
...
@@ -6,17 +6,18 @@ import (
...
@@ -6,17 +6,18 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum-optimism/optimism/indexer/bigint"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
)
)
var
(
var
(
// Standard ABI types copied from golang ABI tests
// Standard ABI types copied from golang ABI tests
uint256Type
,
_
=
abi
.
NewType
(
"uint256"
,
""
,
nil
)
bytesType
,
_
=
abi
.
NewType
(
"bytes"
,
""
,
nil
)
addressType
,
_
=
abi
.
NewType
(
"address"
,
""
,
nil
)
addressType
,
_
=
abi
.
NewType
(
"address"
,
""
,
nil
)
bytesType
,
_
=
abi
.
NewType
(
"bytes"
,
""
,
nil
)
uint256Type
,
_
=
abi
.
NewType
(
"uint256"
,
""
,
nil
)
CrossDomainMessengerLegacyRelayMessageEncoding
=
abi
.
NewMethod
(
CrossDomainMessengerLegacyRelayMessageEncoding
=
abi
.
NewMethod
(
"relayMessage"
,
"relayMessage"
,
...
@@ -39,8 +40,8 @@ var (
...
@@ -39,8 +40,8 @@ var (
type
CrossDomainMessengerSentMessageEvent
struct
{
type
CrossDomainMessengerSentMessageEvent
struct
{
Event
*
database
.
ContractEvent
Event
*
database
.
ContractEvent
MessageCalldata
[]
byte
BridgeMessage
database
.
BridgeMessage
BridgeMessage
database
.
BridgeMessage
Version
uint16
}
}
type
CrossDomainMessengerRelayedMessageEvent
struct
{
type
CrossDomainMessengerRelayedMessageEvent
struct
{
...
@@ -85,13 +86,14 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
...
@@ -85,13 +86,14 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
return
nil
,
err
return
nil
,
err
}
}
version
,
_
:=
DecodeVersionedNonce
(
sentMessage
.
MessageNonce
)
versionBig
,
_
:=
crossdomain
.
DecodeVersionedNonce
(
sentMessage
.
MessageNonce
)
version
:=
uint16
(
versionBig
.
Uint64
())
if
i
<
numVersionZeroMessages
&&
version
!=
0
{
if
i
<
numVersionZeroMessages
&&
version
!=
0
{
return
nil
,
fmt
.
Errorf
(
"expected version zero nonce
. nonce %d
tx_hash %s"
,
sentMessage
.
MessageNonce
,
sentMessage
.
Raw
.
TxHash
)
return
nil
,
fmt
.
Errorf
(
"expected version zero nonce
: nonce %d,
tx_hash %s"
,
sentMessage
.
MessageNonce
,
sentMessage
.
Raw
.
TxHash
)
}
}
// In version zero, to value is bridged through the cross domain messenger.
// In version zero, to value is bridged through the cross domain messenger.
value
:=
big
.
NewInt
(
0
)
value
:=
big
int
.
Zero
if
version
>
0
{
if
version
>
0
{
sentMessageExtension
:=
bindings
.
CrossDomainMessengerSentMessageExtension1
{
Raw
:
*
sentMessageExtensionEvents
[
i
]
.
RLPLog
}
sentMessageExtension
:=
bindings
.
CrossDomainMessengerSentMessageExtension1
{
Raw
:
*
sentMessageExtensionEvents
[
i
]
.
RLPLog
}
err
=
UnpackLog
(
&
sentMessageExtension
,
sentMessageExtensionEvents
[
i
]
.
RLPLog
,
sentMessageExtensionEventAbi
.
Name
,
crossDomainMessengerAbi
)
err
=
UnpackLog
(
&
sentMessageExtension
,
sentMessageExtensionEvents
[
i
]
.
RLPLog
,
sentMessageExtensionEventAbi
.
Name
,
crossDomainMessengerAbi
)
...
@@ -101,16 +103,30 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
...
@@ -101,16 +103,30 @@ func CrossDomainMessengerSentMessageEvents(chainSelector string, contractAddress
value
=
sentMessageExtension
.
Value
value
=
sentMessageExtension
.
Value
}
}
messageCalldata
,
err
:=
CrossDomainMessageCalldata
(
crossDomainMessengerAbi
,
&
sentMessage
,
value
)
var
messageHash
common
.
Hash
switch
version
{
case
0
:
messageHash
,
err
=
crossdomain
.
HashCrossDomainMessageV0
(
sentMessage
.
Target
,
sentMessage
.
Sender
,
sentMessage
.
Message
,
sentMessage
.
MessageNonce
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
case
1
:
messageHash
,
err
=
crossdomain
.
HashCrossDomainMessageV1
(
sentMessage
.
MessageNonce
,
sentMessage
.
Sender
,
sentMessage
.
Target
,
value
,
sentMessage
.
GasLimit
,
sentMessage
.
Message
)
if
err
!=
nil
{
return
nil
,
err
}
default
:
// NOTE: We explicitly fail here since the presence of a new version means finalization
// logic needs to be updated to ensure L1 finalization can run from genesis and handle
// the changing version formats. This is meant to be a serving indicator of this.
return
nil
,
fmt
.
Errorf
(
"expected cross domain version 0 or version 1: %d"
,
version
)
}
crossDomainSentMessages
[
i
]
=
CrossDomainMessengerSentMessageEvent
{
crossDomainSentMessages
[
i
]
=
CrossDomainMessengerSentMessageEvent
{
Event
:
&
sentMessageEvents
[
i
],
Event
:
&
sentMessageEvents
[
i
],
MessageCalldata
:
messageCalldata
,
Version
:
version
,
BridgeMessage
:
database
.
BridgeMessage
{
BridgeMessage
:
database
.
BridgeMessage
{
MessageHash
:
crypto
.
Keccak256Hash
(
messageCalldata
)
,
MessageHash
:
messageHash
,
Nonce
:
sentMessage
.
MessageNonce
,
Nonce
:
sentMessage
.
MessageNonce
,
SentMessageEventGUID
:
sentMessageEvents
[
i
]
.
GUID
,
SentMessageEventGUID
:
sentMessageEvents
[
i
]
.
GUID
,
GasLimit
:
sentMessage
.
GasLimit
,
GasLimit
:
sentMessage
.
GasLimit
,
...
@@ -157,26 +173,3 @@ func CrossDomainMessengerRelayedMessageEvents(chainSelector string, contractAddr
...
@@ -157,26 +173,3 @@ func CrossDomainMessengerRelayedMessageEvents(chainSelector string, contractAddr
return
crossDomainRelayedMessages
,
nil
return
crossDomainRelayedMessages
,
nil
}
}
// Replica of `Encoding.sol#encodeCrossDomainMessage` solidity implementation
func
CrossDomainMessageCalldata
(
abi
*
abi
.
ABI
,
sentMsg
*
bindings
.
CrossDomainMessengerSentMessage
,
value
*
big
.
Int
)
([]
byte
,
error
)
{
version
,
_
:=
DecodeVersionedNonce
(
sentMsg
.
MessageNonce
)
switch
version
{
case
0
:
// Legacy Message
inputBytes
,
err
:=
CrossDomainMessengerLegacyRelayMessageEncoding
.
Inputs
.
Pack
(
sentMsg
.
Target
,
sentMsg
.
Sender
,
sentMsg
.
Message
,
sentMsg
.
MessageNonce
)
if
err
!=
nil
{
return
nil
,
err
}
return
append
(
CrossDomainMessengerLegacyRelayMessageEncoding
.
ID
,
inputBytes
...
),
nil
case
1
:
// Current Message
msgBytes
,
err
:=
abi
.
Pack
(
"relayMessage"
,
sentMsg
.
MessageNonce
,
sentMsg
.
Sender
,
sentMsg
.
Target
,
value
,
sentMsg
.
GasLimit
,
sentMsg
.
Message
)
if
err
!=
nil
{
return
nil
,
err
}
return
msgBytes
,
nil
}
return
nil
,
fmt
.
Errorf
(
"unsupported cross domain messenger version: %d"
,
version
)
}
indexer/processors/contracts/utils.go
View file @
2cf845a9
package
contracts
package
contracts
import
(
import
(
"encoding/binary"
"errors"
"errors"
"fmt"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
)
)
// DecodeVersionNonce is an re-implementation of Encoding.sol#decodeVersionedNonce.
// If the nonce is greater than 32 bytes (solidity uint256), bytes [32:] are ignored
func
DecodeVersionedNonce
(
nonce
*
big
.
Int
)
(
uint16
,
*
big
.
Int
)
{
nonceBytes
:=
nonce
.
Bytes
()
nonceByteLen
:=
len
(
nonceBytes
)
if
nonceByteLen
<
30
{
// version is 0x0000
return
0
,
nonce
}
else
if
nonceByteLen
==
31
{
// version is 0x00[01..ff]
return
uint16
(
nonceBytes
[
0
]),
new
(
big
.
Int
)
.
SetBytes
(
nonceBytes
[
1
:
])
}
else
{
// fully specified
version
:=
binary
.
BigEndian
.
Uint16
(
nonceBytes
[
:
2
])
return
version
,
new
(
big
.
Int
)
.
SetBytes
(
nonceBytes
[
2
:
])
}
}
func
UnpackLog
(
out
interface
{},
log
*
types
.
Log
,
name
string
,
contractAbi
*
abi
.
ABI
)
error
{
func
UnpackLog
(
out
interface
{},
log
*
types
.
Log
,
name
string
,
contractAbi
*
abi
.
ABI
)
error
{
eventAbi
,
ok
:=
contractAbi
.
Events
[
name
]
eventAbi
,
ok
:=
contractAbi
.
Events
[
name
]
if
!
ok
{
if
!
ok
{
...
...
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