Commit 5f128658 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into jg/channel_bank_metric

parents c37e68fa d3f4ec81
......@@ -185,3 +185,37 @@ cd packages/contracts
pip3 install slither-analyzer
pnpm test:slither
```
## Labels
Labels are divided into categories with their descriptions annotated as `<Category Name>: <description>`.
The following are a comprehensive list of label categories.
- **Area labels** ([`A-`][area]): Denote the general area for the related issue or PR changes.
- **Category labels** ([`C-`][category]): Contextualize the type of issue or change.
- **Meta labels** ([`M-`][meta]): These add context to the issues or prs themselves primarily relating to process.
- **Difficulty labels** ([`D-`][difficulty]): Describe the associated implementation's difficulty level.
- **Status labels** ([`S-`][status]): Specify the status of an issue or pr.
Labels also provide a versatile filter for finding tickets that need help or are open for assignment.
This makes them a great tool for contributors!
[area]: https://github.com/ethereum-optimism/optimism/labels?q=a-
[category]: https://github.com/ethereum-optimism/optimism/labels?q=c-
[meta]: https://github.com/ethereum-optimism/optimism/labels?q=m-
[difficulty]: https://github.com/ethereum-optimism/optimism/labels?q=d-
[status]: https://github.com/ethereum-optimism/optimism/labels?q=s-
#### Filtering for Work
To find tickets available for external contribution, take a look at the [`M-community`][M-community] label.
You can filter by the [`D-good-first-issue`][D-good-first-issue]
label to find issues that are intended to be easy to implement or fix.
Also, all labels can be seen by visiting the [labels page][labels]
[labels]: https://github.com/ethereum-optimism/optimism/labels
[M-community]: https://github.com/ethereum-optimism/optimism/labels/M-community
[D-good-first-issue]: https://github.com/ethereum-optimism/optimism/labels/D-good-first-issue
......@@ -2,7 +2,6 @@ package api
import (
"fmt"
"math/big"
"net/http"
"net/http/httptest"
"testing"
......@@ -21,17 +20,21 @@ var mockAddress = "0x4204204204204204204204204204204204204204"
var (
deposit = database.L1BridgeDeposit{
TransactionSourceHash: common.HexToHash("abc"),
CrossDomainMessengerNonce: &database.U256{Int: big.NewInt(0)},
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
TransactionSourceHash: common.HexToHash("abc"),
BridgeTransfer: database.BridgeTransfer{
CrossDomainMessageHash: &common.Hash{},
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
},
}
withdrawal = database.L2BridgeWithdrawal{
TransactionWithdrawalHash: common.HexToHash("0x420"),
CrossDomainMessengerNonce: &database.U256{Int: big.NewInt(0)},
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
BridgeTransfer: database.BridgeTransfer{
CrossDomainMessageHash: &common.Hash{},
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
},
}
)
......@@ -39,7 +42,7 @@ func (mbv *MockBridgeTransfersView) L1BridgeDeposit(hash common.Hash) (*database
return &deposit, nil
}
func (mbv *MockBridgeTransfersView) L1BridgeDepositByCrossDomainMessengerNonce(nonce *big.Int) (*database.L1BridgeDeposit, error) {
func (mbv *MockBridgeTransfersView) L1BridgeDepositWithFilter(filter database.BridgeTransfer) (*database.L1BridgeDeposit, error) {
return &deposit, nil
}
......@@ -56,7 +59,7 @@ func (mbv *MockBridgeTransfersView) L2BridgeWithdrawal(address common.Hash) (*da
return &withdrawal, nil
}
func (mbv *MockBridgeTransfersView) L2BridgeWithdrawalByCrossDomainMessengerNonce(nonce *big.Int) (*database.L2BridgeWithdrawal, error) {
func (mbv *MockBridgeTransfersView) L2BridgeWithdrawalWithFilter(filter database.BridgeTransfer) (*database.L2BridgeWithdrawal, error) {
return &withdrawal, nil
}
......
......@@ -48,7 +48,7 @@ func newDepositResponse(deposits []*database.L1BridgeDepositWithTransactionHashe
Amount: deposit.L1BridgeDeposit.Tx.Amount.Int.String(),
L1Token: TokenInfo{
ChainId: 1,
Address: deposit.L1BridgeDeposit.TokenPair.L1TokenAddress.String(),
Address: deposit.L1BridgeDeposit.TokenPair.LocalTokenAddress.String(),
Name: "TODO",
Symbol: "TODO",
Decimals: 420,
......@@ -58,7 +58,7 @@ func newDepositResponse(deposits []*database.L1BridgeDepositWithTransactionHashe
},
L2Token: TokenInfo{
ChainId: 10,
Address: deposit.L1BridgeDeposit.TokenPair.L2TokenAddress.String(),
Address: deposit.L1BridgeDeposit.TokenPair.RemoteTokenAddress.String(),
Name: "TODO",
Symbol: "TODO",
Decimals: 420,
......
......@@ -73,7 +73,7 @@ func newWithdrawalResponse(withdrawals []*database.L2BridgeWithdrawalWithTransac
WithdrawalState: "COMPLETE", // TODO
L1Token: TokenInfo{
ChainId: 1,
Address: withdrawal.L2BridgeWithdrawal.TokenPair.L1TokenAddress.String(),
Address: withdrawal.L2BridgeWithdrawal.TokenPair.RemoteTokenAddress.String(),
Name: "Example", // TODO
Symbol: "EXAMPLE", // TODO
Decimals: 18, // TODO
......@@ -83,7 +83,7 @@ func newWithdrawalResponse(withdrawals []*database.L2BridgeWithdrawalWithTransac
},
L2Token: TokenInfo{
ChainId: 10,
Address: withdrawal.L2BridgeWithdrawal.TokenPair.L2TokenAddress.String(),
Address: withdrawal.L2BridgeWithdrawal.TokenPair.LocalTokenAddress.String(),
Name: "Example", // TODO
Symbol: "EXAMPLE", // TODO
Decimals: 18, // TODO
......
......@@ -3,7 +3,6 @@ package database
import (
"errors"
"fmt"
"math/big"
"gorm.io/gorm"
......@@ -17,8 +16,8 @@ import (
*/
type BridgeMessage struct {
Nonce U256 `gorm:"primaryKey"`
MessageHash common.Hash `gorm:"serializer:json"`
MessageHash common.Hash `gorm:"primaryKey;serializer:json"`
Nonce U256
SentMessageEventGUID uuid.UUID
RelayedMessageEventGUID *uuid.UUID
......@@ -38,13 +37,11 @@ type L2BridgeMessage struct {
}
type BridgeMessagesView interface {
L1BridgeMessage(*big.Int) (*L1BridgeMessage, error)
L1BridgeMessageByHash(common.Hash) (*L1BridgeMessage, error)
LatestL1BridgeMessageNonce() (*big.Int, error)
L1BridgeMessage(common.Hash) (*L1BridgeMessage, error)
L1BridgeMessageWithFilter(BridgeMessage) (*L1BridgeMessage, error)
L2BridgeMessage(*big.Int) (*L2BridgeMessage, error)
L2BridgeMessageByHash(common.Hash) (*L2BridgeMessage, error)
LatestL2BridgeMessageNonce() (*big.Int, error)
L2BridgeMessage(common.Hash) (*L2BridgeMessage, error)
L2BridgeMessageWithFilter(BridgeMessage) (*L2BridgeMessage, error)
}
type BridgeMessagesDB interface {
......@@ -78,22 +75,13 @@ func (db bridgeMessagesDB) StoreL1BridgeMessages(messages []*L1BridgeMessage) er
return result.Error
}
func (db bridgeMessagesDB) L1BridgeMessage(nonce *big.Int) (*L1BridgeMessage, error) {
var sentMessage L1BridgeMessage
result := db.gorm.Where(&BridgeMessage{Nonce: U256{Int: nonce}}).Take(&sentMessage)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &sentMessage, nil
func (db bridgeMessagesDB) L1BridgeMessage(msgHash common.Hash) (*L1BridgeMessage, error) {
return db.L1BridgeMessageWithFilter(BridgeMessage{MessageHash: msgHash})
}
func (db bridgeMessagesDB) L1BridgeMessageByHash(messageHash common.Hash) (*L1BridgeMessage, error) {
func (db bridgeMessagesDB) L1BridgeMessageWithFilter(filter BridgeMessage) (*L1BridgeMessage, error) {
var sentMessage L1BridgeMessage
result := db.gorm.Where(&BridgeMessage{MessageHash: messageHash}).Take(&sentMessage)
result := db.gorm.Where(&filter).Take(&sentMessage)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
......@@ -104,25 +92,8 @@ func (db bridgeMessagesDB) L1BridgeMessageByHash(messageHash common.Hash) (*L1Br
return &sentMessage, nil
}
func (db bridgeMessagesDB) LatestL1BridgeMessageNonce() (*big.Int, error) {
var sentMessage L1BridgeMessage
result := db.gorm.Order("nonce DESC").Take(&sentMessage)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return sentMessage.Nonce.Int, nil
}
/**
* Arbitrary Messages Sent from L2
*/
func (db bridgeMessagesDB) MarkRelayedL1BridgeMessage(messageHash common.Hash, relayEvent uuid.UUID) error {
message, err := db.L1BridgeMessageByHash(messageHash)
message, err := db.L1BridgeMessage(messageHash)
if err != nil {
return err
} else if message == nil {
......@@ -134,27 +105,22 @@ func (db bridgeMessagesDB) MarkRelayedL1BridgeMessage(messageHash common.Hash, r
return result.Error
}
/**
* Arbitrary Messages Sent from L2
*/
func (db bridgeMessagesDB) StoreL2BridgeMessages(messages []*L2BridgeMessage) error {
result := db.gorm.Create(&messages)
return result.Error
}
func (db bridgeMessagesDB) L2BridgeMessage(nonce *big.Int) (*L2BridgeMessage, error) {
var sentMessage L2BridgeMessage
result := db.gorm.Where(&BridgeMessage{Nonce: U256{Int: nonce}}).Take(&sentMessage)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &sentMessage, nil
func (db bridgeMessagesDB) L2BridgeMessage(msgHash common.Hash) (*L2BridgeMessage, error) {
return db.L2BridgeMessageWithFilter(BridgeMessage{MessageHash: msgHash})
}
func (db bridgeMessagesDB) L2BridgeMessageByHash(messageHash common.Hash) (*L2BridgeMessage, error) {
func (db bridgeMessagesDB) L2BridgeMessageWithFilter(filter BridgeMessage) (*L2BridgeMessage, error) {
var sentMessage L2BridgeMessage
result := db.gorm.Where(&BridgeMessage{MessageHash: messageHash}).Take(&sentMessage)
result := db.gorm.Where(&filter).Take(&sentMessage)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
......@@ -165,21 +131,8 @@ func (db bridgeMessagesDB) L2BridgeMessageByHash(messageHash common.Hash) (*L2Br
return &sentMessage, nil
}
func (db bridgeMessagesDB) LatestL2BridgeMessageNonce() (*big.Int, error) {
var sentMessage L2BridgeMessage
result := db.gorm.Order("nonce DESC").Take(&sentMessage)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return sentMessage.Nonce.Int, nil
}
func (db bridgeMessagesDB) MarkRelayedL2BridgeMessage(messageHash common.Hash, relayEvent uuid.UUID) error {
message, err := db.L2BridgeMessageByHash(messageHash)
message, err := db.L2BridgeMessage(messageHash)
if err != nil {
return err
} else if message == nil {
......
......@@ -24,21 +24,16 @@ type Transaction struct {
}
type L1TransactionDeposit struct {
SourceHash common.Hash `gorm:"serializer:json;primaryKey"`
L2TransactionHash common.Hash `gorm:"serializer:json"`
SourceHash common.Hash `gorm:"serializer:json;primaryKey"`
L2TransactionHash common.Hash `gorm:"serializer:json"`
InitiatedL1EventGUID uuid.UUID
Version U256
OpaqueData hexutil.Bytes `gorm:"serializer:json"`
Tx Transaction `gorm:"embedded"`
GasLimit U256
}
type L2TransactionWithdrawal struct {
WithdrawalHash common.Hash `gorm:"serializer:json;primaryKey"`
WithdrawalHash common.Hash `gorm:"serializer:json;primaryKey"`
Nonce U256
InitiatedL2EventGUID uuid.UUID
......
......@@ -2,31 +2,39 @@ package database
import (
"errors"
"math/big"
"gorm.io/gorm"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
)
var (
ETHTokenPair = TokenPair{LocalTokenAddress: predeploys.LegacyERC20ETHAddr, RemoteTokenAddress: predeploys.LegacyERC20ETHAddr}
)
/**
* Types
*/
type TokenPair struct {
L1TokenAddress common.Address `gorm:"serializer:json"`
L2TokenAddress common.Address `gorm:"serializer:json"`
LocalTokenAddress common.Address `gorm:"serializer:json"`
RemoteTokenAddress common.Address `gorm:"serializer:json"`
}
type L1BridgeDeposit struct {
TransactionSourceHash common.Hash `gorm:"primaryKey;serializer:json"`
CrossDomainMessengerNonce *U256
type BridgeTransfer struct {
CrossDomainMessageHash *common.Hash `gorm:"serializer:json"`
Tx Transaction `gorm:"embedded"`
TokenPair TokenPair `gorm:"embedded"`
}
type L1BridgeDeposit struct {
BridgeTransfer `gorm:"embedded"`
TransactionSourceHash common.Hash `gorm:"primaryKey;serializer:json"`
}
type L1BridgeDepositWithTransactionHashes struct {
L1BridgeDeposit L1BridgeDeposit `gorm:"embedded"`
......@@ -35,12 +43,9 @@ type L1BridgeDepositWithTransactionHashes struct {
}
type L2BridgeWithdrawal struct {
TransactionWithdrawalHash common.Hash `gorm:"primaryKey;serializer:json"`
CrossDomainMessengerNonce *U256
BridgeTransfer `gorm:"embedded"`
Tx Transaction `gorm:"embedded"`
TokenPair TokenPair `gorm:"embedded"`
TransactionWithdrawalHash common.Hash `gorm:"primaryKey;serializer:json"`
}
type L2BridgeWithdrawalWithTransactionHashes struct {
......@@ -53,11 +58,11 @@ type L2BridgeWithdrawalWithTransactionHashes struct {
type BridgeTransfersView interface {
L1BridgeDeposit(common.Hash) (*L1BridgeDeposit, error)
L1BridgeDepositByCrossDomainMessengerNonce(*big.Int) (*L1BridgeDeposit, error)
L1BridgeDepositWithFilter(BridgeTransfer) (*L1BridgeDeposit, error)
L1BridgeDepositsByAddress(common.Address) ([]*L1BridgeDepositWithTransactionHashes, error)
L2BridgeWithdrawal(common.Hash) (*L2BridgeWithdrawal, error)
L2BridgeWithdrawalByCrossDomainMessengerNonce(*big.Int) (*L2BridgeWithdrawal, error)
L2BridgeWithdrawalWithFilter(BridgeTransfer) (*L2BridgeWithdrawal, error)
L2BridgeWithdrawalsByAddress(common.Address) ([]*L2BridgeWithdrawalWithTransactionHashes, error)
}
......@@ -104,9 +109,9 @@ func (db *bridgeTransfersDB) L1BridgeDeposit(txSourceHash common.Hash) (*L1Bridg
// L1BridgeDepositByCrossDomainMessengerNonce retrieves tokens deposited, specified by the associated `L1CrossDomainMessenger` nonce.
// All tokens bridged via the StandardBridge flows through the L1CrossDomainMessenger
func (db *bridgeTransfersDB) L1BridgeDepositByCrossDomainMessengerNonce(nonce *big.Int) (*L1BridgeDeposit, error) {
func (db *bridgeTransfersDB) L1BridgeDepositWithFilter(filter BridgeTransfer) (*L1BridgeDeposit, error) {
var deposit L1BridgeDeposit
result := db.gorm.Where(&L1BridgeDeposit{CrossDomainMessengerNonce: &U256{Int: nonce}}).Take(&deposit)
result := db.gorm.Where(&filter).Take(&deposit)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
......@@ -168,9 +173,9 @@ func (db *bridgeTransfersDB) L2BridgeWithdrawal(txWithdrawalHash common.Hash) (*
// L2BridgeWithdrawalByCrossDomainMessengerNonce retrieves tokens withdrawn, specified by the associated `L2CrossDomainMessenger` nonce.
// All tokens bridged via the StandardBridge flows through the L2CrossDomainMessenger
func (db *bridgeTransfersDB) L2BridgeWithdrawalByCrossDomainMessengerNonce(nonce *big.Int) (*L2BridgeWithdrawal, error) {
func (db *bridgeTransfersDB) L2BridgeWithdrawalWithFilter(filter BridgeTransfer) (*L2BridgeWithdrawal, error) {
var withdrawal L2BridgeWithdrawal
result := db.gorm.Where(&L2BridgeWithdrawal{CrossDomainMessengerNonce: &U256{Int: nonce}}).Take(&withdrawal)
result := db.gorm.Where(filter).Take(&withdrawal)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
......
......@@ -57,12 +57,12 @@ func TestE2EBridgeL1CrossDomainMessenger(t *testing.T) {
nonceBytes := [31]byte{0: byte(1)}
nonce := new(big.Int).SetBytes(nonceBytes[:])
sentMessage, err := testSuite.DB.BridgeMessages.L1BridgeMessage(nonce)
sentMessage, err := testSuite.DB.BridgeMessages.L1BridgeMessage(parsedMessage.MessageHash)
require.NoError(t, err)
require.NotNil(t, sentMessage)
require.NotNil(t, sentMessage.SentMessageEventGUID)
require.Equal(t, depositInfo.DepositTx.SourceHash, sentMessage.TransactionSourceHash)
require.Equal(t, parsedMessage.MessageHash, sentMessage.MessageHash)
require.Equal(t, nonce.Uint64(), sentMessage.Nonce.Int.Uint64())
require.Equal(t, uint64(100_000), sentMessage.GasLimit.Int.Uint64())
require.Equal(t, big.NewInt(params.Ether), sentMessage.Tx.Amount.Int)
require.Equal(t, aliceAddr, sentMessage.Tx.FromAddress)
......@@ -83,7 +83,7 @@ func TestE2EBridgeL1CrossDomainMessenger(t *testing.T) {
return l2Header != nil && l2Header.Number.Uint64() >= depositReceipt.BlockNumber.Uint64(), nil
}))
sentMessage, err = testSuite.DB.BridgeMessages.L1BridgeMessage(nonce)
sentMessage, err = testSuite.DB.BridgeMessages.L1BridgeMessage(parsedMessage.MessageHash)
require.NoError(t, err)
require.NotNil(t, sentMessage)
require.NotNil(t, sentMessage.RelayedMessageEventGUID)
......@@ -143,12 +143,12 @@ func TestE2EBridgeL2CrossDomainMessenger(t *testing.T) {
nonceBytes := [31]byte{0: byte(1)}
nonce := new(big.Int).SetBytes(nonceBytes[:])
sentMessage, err := testSuite.DB.BridgeMessages.L2BridgeMessage(nonce)
sentMessage, err := testSuite.DB.BridgeMessages.L2BridgeMessage(parsedMessage.MessageHash)
require.NoError(t, err)
require.NotNil(t, sentMessage)
require.NotNil(t, sentMessage.SentMessageEventGUID)
require.Equal(t, withdrawalHash, sentMessage.TransactionWithdrawalHash)
require.Equal(t, parsedMessage.MessageHash, sentMessage.MessageHash)
require.Equal(t, nonce.Uint64(), sentMessage.Nonce.Int.Uint64())
require.Equal(t, uint64(100_000), sentMessage.GasLimit.Int.Uint64())
require.Equal(t, big.NewInt(params.Ether), sentMessage.Tx.Amount.Int)
require.Equal(t, aliceAddr, sentMessage.Tx.FromAddress)
......@@ -166,7 +166,7 @@ func TestE2EBridgeL2CrossDomainMessenger(t *testing.T) {
}))
// message is marked as relayed
sentMessage, err = testSuite.DB.BridgeMessages.L2BridgeMessage(nonce)
sentMessage, err = testSuite.DB.BridgeMessages.L2BridgeMessage(parsedMessage.MessageHash)
require.NoError(t, err)
require.NotNil(t, sentMessage)
require.NotNil(t, sentMessage.RelayedMessageEventGUID)
......
......@@ -59,9 +59,6 @@ func TestE2EBridgeTransactionsOptimismPortalDeposits(t *testing.T) {
require.Equal(t, aliceAddr, deposit.Tx.ToAddress)
require.ElementsMatch(t, calldata, deposit.Tx.Data)
require.Equal(t, depositInfo.Version.Uint64(), deposit.Version.Int.Uint64())
require.ElementsMatch(t, depositInfo.OpaqueData, deposit.OpaqueData)
event, err := testSuite.DB.ContractEvents.L1ContractEvent(deposit.InitiatedL1EventGUID)
require.NoError(t, err)
require.NotNil(t, event)
......
......@@ -7,7 +7,6 @@ import (
"time"
e2etest_utils "github.com/ethereum-optimism/optimism/indexer/e2e_tests/utils"
"github.com/ethereum-optimism/optimism/indexer/processor"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
......@@ -56,8 +55,8 @@ func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
deposit := aliceDeposits[0].L1BridgeDeposit
require.Equal(t, depositInfo.DepositTx.SourceHash, deposit.TransactionSourceHash)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.L1TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.L2TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.LocalTokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.RemoteTokenAddress)
require.Equal(t, big.NewInt(params.Ether), deposit.Tx.Amount.Int)
require.Equal(t, aliceAddr, deposit.Tx.FromAddress)
require.Equal(t, aliceAddr, deposit.Tx.ToAddress)
......@@ -65,9 +64,7 @@ func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
// StandardBridge flows through the messenger. We remove the first two significant
// bytes of the nonce dedicated to the version. nonce == 0 (first message)
require.NotNil(t, deposit.CrossDomainMessengerNonce)
_, nonce := processor.DecodeVersionedNonce(deposit.CrossDomainMessengerNonce.Int)
require.Zero(t, nonce.Uint64())
require.NotNil(t, deposit.CrossDomainMessageHash)
// (2) Test Deposit Finalization via CrossDomainMessenger relayed message
depositReceipt, err = wait.ForReceiptOK(context.Background(), testSuite.L2Client, types.NewTx(depositInfo.DepositTx).Hash())
......@@ -77,7 +74,7 @@ func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
return l2Header != nil && l2Header.Number.Uint64() >= depositReceipt.BlockNumber.Uint64(), nil
}))
crossDomainBridgeMessage, err := testSuite.DB.BridgeMessages.L1BridgeMessage(deposit.CrossDomainMessengerNonce.Int)
crossDomainBridgeMessage, err := testSuite.DB.BridgeMessages.L1BridgeMessage(*deposit.CrossDomainMessageHash)
require.NoError(t, err)
require.NotNil(t, crossDomainBridgeMessage)
require.NotNil(t, crossDomainBridgeMessage.RelayedMessageEventGUID)
......@@ -117,18 +114,28 @@ func TestE2EBridgeTransfersOptimismPortalETHReceive(t *testing.T) {
deposit := aliceDeposits[0].L1BridgeDeposit
require.Equal(t, depositInfo.DepositTx.SourceHash, deposit.TransactionSourceHash)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.L1TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.L2TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.LocalTokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.RemoteTokenAddress)
require.Equal(t, big.NewInt(params.Ether), deposit.Tx.Amount.Int)
require.Equal(t, aliceAddr, deposit.Tx.FromAddress)
require.Equal(t, aliceAddr, deposit.Tx.ToAddress)
require.Len(t, deposit.Tx.Data, 0)
// deposit was not sent through the cross domain messenger
require.Nil(t, deposit.CrossDomainMessengerNonce)
require.Nil(t, deposit.CrossDomainMessageHash)
// (2) Test Deposit Finalization
// Nothing to do as we rely on the derivation process to include the deposit
depositReceipt, err := wait.ForReceiptOK(context.Background(), testSuite.L2Client, types.NewTx(depositInfo.DepositTx).Hash())
require.NoError(t, err)
require.NoError(t, wait.For(context.Background(), 500*time.Millisecond, func() (bool, error) {
l2Header := testSuite.Indexer.L2Processor.LatestProcessedHeader()
return l2Header != nil && l2Header.Number.Uint64() >= depositReceipt.BlockNumber.Uint64(), nil
}))
// Still nil as the withdrawal did not occur through the standard bridge
aliceDeposits, err = testSuite.DB.BridgeTransfers.L1BridgeDepositsByAddress(aliceAddr)
require.NoError(t, err)
require.Nil(t, aliceDeposits[0].L1BridgeDeposit.CrossDomainMessageHash)
}
func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
......@@ -178,8 +185,8 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
withdrawal := aliceWithdrawals[0].L2BridgeWithdrawal
require.Equal(t, withdrawalHash, withdrawal.TransactionWithdrawalHash)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.L1TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.L2TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.LocalTokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.RemoteTokenAddress)
require.Equal(t, big.NewInt(params.Ether), withdrawal.Tx.Amount.Int)
require.Equal(t, aliceAddr, withdrawal.Tx.FromAddress)
require.Equal(t, aliceAddr, withdrawal.Tx.ToAddress)
......@@ -187,9 +194,11 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
// StandardBridge flows through the messenger. We remove the first two
// bytes of the nonce dedicated to the version. nonce == 0 (first message)
require.NotNil(t, withdrawal.CrossDomainMessengerNonce)
_, nonce := processor.DecodeVersionedNonce(withdrawal.CrossDomainMessengerNonce.Int)
require.Zero(t, nonce.Uint64())
require.NotNil(t, withdrawal.CrossDomainMessageHash)
crossDomainBridgeMessage, err := testSuite.DB.BridgeMessages.L2BridgeMessage(*withdrawal.CrossDomainMessageHash)
require.NoError(t, err)
require.Nil(t, crossDomainBridgeMessage.RelayedMessageEventGUID)
// (2) Test Withdrawal Proven/Finalized. Test the sql join queries to populate the right transaction
require.Empty(t, aliceWithdrawals[0].ProvenL1TransactionHash)
......@@ -206,6 +215,11 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
require.NoError(t, err)
require.Equal(t, proveReceipt.TxHash, aliceWithdrawals[0].ProvenL1TransactionHash)
require.Equal(t, finalizeReceipt.TxHash, aliceWithdrawals[0].FinalizedL1TransactionHash)
crossDomainBridgeMessage, err = testSuite.DB.BridgeMessages.L2BridgeMessage(*withdrawal.CrossDomainMessageHash)
require.NoError(t, err)
require.NotNil(t, crossDomainBridgeMessage)
require.NotNil(t, crossDomainBridgeMessage.RelayedMessageEventGUID)
}
func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {
......@@ -254,15 +268,15 @@ func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {
withdrawal := aliceWithdrawals[0].L2BridgeWithdrawal
require.Equal(t, withdrawalHash, withdrawal.TransactionWithdrawalHash)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.L1TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.L2TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.LocalTokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.RemoteTokenAddress)
require.Equal(t, big.NewInt(params.Ether), withdrawal.Tx.Amount.Int)
require.Equal(t, aliceAddr, withdrawal.Tx.FromAddress)
require.Equal(t, aliceAddr, withdrawal.Tx.ToAddress)
require.Len(t, withdrawal.Tx.Data, 0)
// withdrawal was not sent through the cross domain messenger
require.Nil(t, withdrawal.CrossDomainMessengerNonce)
require.Nil(t, withdrawal.CrossDomainMessageHash)
// (2) Test Withdrawal Proven/Finalized. Test the sql join queries to populate the right transaction
require.Empty(t, aliceWithdrawals[0].ProvenL1TransactionHash)
......@@ -279,4 +293,7 @@ func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {
require.NoError(t, err)
require.Equal(t, proveReceipt.TxHash, aliceWithdrawals[0].ProvenL1TransactionHash)
require.Equal(t, finalizeReceipt.TxHash, aliceWithdrawals[0].FinalizedL1TransactionHash)
// Still nil as the withdrawal did not occur through the standard bridge
require.Nil(t, aliceWithdrawals[0].L2BridgeWithdrawal.CrossDomainMessageHash)
}
......@@ -116,10 +116,6 @@ CREATE TABLE IF NOT EXISTS l1_transaction_deposits (
initiated_l1_event_guid VARCHAR NOT NULL REFERENCES l1_contract_events(guid),
-- OptimismPortal specific
version UINT256 NOT NULL,
opaque_data VARCHAR NOT NULL,
-- transaction data
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
......@@ -152,9 +148,10 @@ CREATE TABLE IF NOT EXISTS l2_transaction_withdrawals (
-- CrossDomainMessenger
CREATE TABLE IF NOT EXISTS l1_bridge_messages(
nonce UINT256 NOT NULL PRIMARY KEY,
message_hash VARCHAR NOT NULL,
transaction_source_hash VARCHAR NOT NULL REFERENCES l1_transaction_deposits(source_hash),
message_hash VARCHAR NOT NULL PRIMARY KEY,
nonce UINT256 NOT NULL UNIQUE,
transaction_source_hash VARCHAR NOT NULL UNIQUE REFERENCES l1_transaction_deposits(source_hash),
sent_message_event_guid VARCHAR NOT NULL UNIQUE REFERENCES l1_contract_events(guid),
relayed_message_event_guid VARCHAR UNIQUE REFERENCES l2_contract_events(guid),
......@@ -168,9 +165,10 @@ CREATE TABLE IF NOT EXISTS l1_bridge_messages(
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
);
CREATE TABLE IF NOT EXISTS l2_bridge_messages(
nonce UINT256 NOT NULL PRIMARY KEY,
message_hash VARCHAR NOT NULL,
transaction_withdrawal_hash VARCHAR NOT NULL REFERENCES l2_transaction_withdrawals(withdrawal_hash),
message_hash VARCHAR NOT NULL PRIMARY KEY,
nonce UINT256 NOT NULL UNIQUE,
transaction_withdrawal_hash VARCHAR NOT NULL UNIQUE REFERENCES l2_transaction_withdrawals(withdrawal_hash),
sent_message_event_guid VARCHAR NOT NULL UNIQUE REFERENCES l2_contract_events(guid),
relayed_message_event_guid VARCHAR UNIQUE REFERENCES l1_contract_events(guid),
......@@ -188,15 +186,15 @@ CREATE TABLE IF NOT EXISTS l2_bridge_messages(
CREATE TABLE IF NOT EXISTS l1_bridge_deposits (
transaction_source_hash VARCHAR PRIMARY KEY REFERENCES l1_transaction_deposits(source_hash),
-- We allow the cross_domain_messenger_nonce to be NULL-able to account
-- We allow the cross_domain_message_hash to be NULL-able to account
-- for scenarios where ETH is simply sent to the OptimismPortal contract
cross_domain_messenger_nonce UINT256 UNIQUE REFERENCES l1_bridge_messages(nonce),
cross_domain_message_hash VARCHAR UNIQUE REFERENCES l1_bridge_messages(message_hash),
-- Deposit information
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
l1_token_address VARCHAR NOT NULL, -- REFERENCES l1_tokens(address), uncomment me in future pr
l2_token_address VARCHAR NOT NULL, -- REFERENCES l2_tokens(address), uncomment me in future pr
local_token_address VARCHAR NOT NULL, -- REFERENCES l1_tokens(address), uncomment me in future pr
remote_token_address VARCHAR NOT NULL, -- REFERENCES l2_tokens(address), uncomment me in future pr
amount UINT256 NOT NULL,
data VARCHAR NOT NULL,
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
......@@ -204,15 +202,15 @@ CREATE TABLE IF NOT EXISTS l1_bridge_deposits (
CREATE TABLE IF NOT EXISTS l2_bridge_withdrawals (
transaction_withdrawal_hash VARCHAR PRIMARY KEY REFERENCES l2_transaction_withdrawals(withdrawal_hash),
-- We allow the cross_domain_messenger_nonce to be NULL-able to account for
-- We allow the cross_domain_message_hash to be NULL-able to account for
-- scenarios where ETH is simply sent to the L2ToL1MessagePasser contract
cross_domain_messenger_nonce UINT256 UNIQUE REFERENCES l2_bridge_messages(nonce),
cross_domain_message_hash VARCHAR UNIQUE REFERENCES l2_bridge_messages(message_hash),
-- Withdrawal information
from_address VARCHAR NOT NULL,
to_address VARCHAR NOT NULL,
l1_token_address VARCHAR NOT NULL, -- REFERENCES l1_tokens(address), uncomment me in future pr
l2_token_address VARCHAR NOT NULL, -- REFERENCES l2_tokens(address), uncomment me in future pr
local_token_address VARCHAR NOT NULL, -- REFERENCES l2_tokens(address), uncomment me in future pr
remote_token_address VARCHAR NOT NULL, -- REFERENCES l1_tokens(address), uncomment me in future pr
amount UINT256 NOT NULL,
data VARCHAR NOT NULL,
timestamp INTEGER NOT NULL CHECK (timestamp > 0)
......
......@@ -12,7 +12,6 @@ import (
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum"
......@@ -222,7 +221,7 @@ func l1ProcessFn(processLog log.Logger, ethClient node.EthClient, l1Contracts co
}
// forward along contract events to standard bridge processor
err = l1ProcessContractEventsStandardBridge(processLog, db, ethClient, processedContractEvents)
err = l1ProcessContractEventsStandardBridge(processLog, db, processedContractEvents)
if err != nil {
return err
}
......@@ -250,8 +249,6 @@ func l1ProcessContractEventsBridgeTransactions(processLog log.Logger, db *databa
SourceHash: depositTx.SourceHash,
L2TransactionHash: types.NewTx(depositTx).Hash(),
InitiatedL1EventGUID: depositEvent.Event.GUID,
Version: database.U256{Int: depositEvent.Version},
OpaqueData: depositEvent.OpaqueData,
GasLimit: database.U256{Int: new(big.Int).SetUint64(depositTx.Gas)},
Tx: database.Transaction{
FromAddress: depositTx.From,
......@@ -266,11 +263,10 @@ func l1ProcessContractEventsBridgeTransactions(processLog log.Logger, db *databa
if len(depositTx.Data) == 0 && depositTx.Value.BitLen() > 0 {
ethDeposits = append(ethDeposits, &database.L1BridgeDeposit{
TransactionSourceHash: depositTx.SourceHash,
Tx: transactionDeposits[i].Tx,
TokenPair: database.TokenPair{
BridgeTransfer: database.BridgeTransfer{
Tx: transactionDeposits[i].Tx,
// TODO index eth token if it doesn't exist
L1TokenAddress: predeploys.LegacyERC20ETHAddr,
L2TokenAddress: predeploys.LegacyERC20ETHAddr,
TokenPair: database.ETHTokenPair,
},
})
}
......@@ -386,8 +382,8 @@ func l1ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
sentMessages[i] = &database.L1BridgeMessage{
TransactionSourceHash: depositTx.SourceHash,
BridgeMessage: database.BridgeMessage{
Nonce: database.U256{Int: sentMessageEvent.MessageNonce},
MessageHash: sentMessageEvent.MessageHash,
Nonce: database.U256{Int: sentMessageEvent.MessageNonce},
SentMessageEventGUID: sentMessageEvent.Event.GUID,
GasLimit: database.U256{Int: sentMessageEvent.GasLimit},
Tx: database.Transaction{
......@@ -419,7 +415,7 @@ func l1ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
}
for _, relayedMessage := range relayedMessageEvents {
message, err := db.BridgeMessages.L2BridgeMessageByHash(relayedMessage.MsgHash)
message, err := db.BridgeMessages.L2BridgeMessage(relayedMessage.MsgHash)
if err != nil {
return err
} else if message == nil {
......@@ -443,9 +439,7 @@ func l1ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
return nil
}
func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.DB, ethClient node.EthClient, events *ProcessedContractEvents) error {
rawEthClient := ethclient.NewClient(ethClient.RawRpcClient())
func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.DB, events *ProcessedContractEvents) error {
// (1) Process New Deposits
initiatedDepositEvents, err := StandardBridgeInitiatedEvents(events)
if err != nil {
......@@ -465,16 +459,18 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
}
deposits[i] = &database.L1BridgeDeposit{
TransactionSourceHash: depositTx.SourceHash,
CrossDomainMessengerNonce: &database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce},
// TODO index the tokens pairs if they don't exist
TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From,
ToAddress: initiatedBridgeEvent.To,
Amount: database.U256{Int: initiatedBridgeEvent.Amount},
Data: initiatedBridgeEvent.ExtraData,
Timestamp: initiatedBridgeEvent.Event.Timestamp,
TransactionSourceHash: depositTx.SourceHash,
BridgeTransfer: database.BridgeTransfer{
CrossDomainMessageHash: &initiatedBridgeEvent.CrossDomainMessageHash,
// TODO index the tokens pairs if they don't exist
TokenPair: database.TokenPair{LocalTokenAddress: initiatedBridgeEvent.LocalToken, RemoteTokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From,
ToAddress: initiatedBridgeEvent.To,
Amount: database.U256{Int: initiatedBridgeEvent.Amount},
Data: initiatedBridgeEvent.ExtraData,
Timestamp: initiatedBridgeEvent.Event.Timestamp,
},
},
}
}
......@@ -491,26 +487,25 @@ func l1ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
// - We dont need do anything actionable on the database here as this is layered on top of the
// bridge transaction & messages that have a tracked lifecyle. We simply walk through and ensure
// that the corresponding initiated withdrawals exist and match as an integrity check
finalizedWithdrawalEvents, err := StandardBridgeFinalizedEvents(rawEthClient, events)
finalizedWithdrawalEvents, err := StandardBridgeFinalizedEvents(events)
if err != nil {
return err
}
for _, finalizedWithdrawalEvent := range finalizedWithdrawalEvents {
withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalByCrossDomainMessengerNonce(finalizedWithdrawalEvent.CrossDomainMessengerNonce)
withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &finalizedWithdrawalEvent.CrossDomainMessageHash})
if err != nil {
return err
} else if withdrawal == nil {
processLog.Error("missing indexed L2StandardBridge withdrawal for finalization", "cross_domain_messenger_nonce", finalizedWithdrawalEvent.CrossDomainMessengerNonce)
processLog.Error("missing indexed L2StandardBridge withdrawal for finalization", "cross_domain_message_hash", finalizedWithdrawalEvent.CrossDomainMessageHash)
return errors.New("missing indexed L2StandardBridge withdrawal for finalization event")
}
// sanity check on the bridge fields
if finalizedWithdrawalEvent.From != withdrawal.Tx.FromAddress || finalizedWithdrawalEvent.To != withdrawal.Tx.ToAddress ||
finalizedWithdrawalEvent.Amount.Cmp(withdrawal.Tx.Amount.Int) != 0 || !bytes.Equal(finalizedWithdrawalEvent.ExtraData, withdrawal.Tx.Data) ||
finalizedWithdrawalEvent.LocalToken != withdrawal.TokenPair.L1TokenAddress || finalizedWithdrawalEvent.RemoteToken != withdrawal.TokenPair.L2TokenAddress {
processLog.Crit("bridge finalization fields mismatch with initiated fields!", "tx_withdrawal_hash", withdrawal.TransactionWithdrawalHash, "cross_domain_messenger_nonce", withdrawal.CrossDomainMessengerNonce.Int)
return errors.New("bridge tx mismatch!")
finalizedWithdrawalEvent.LocalToken != withdrawal.TokenPair.LocalTokenAddress || finalizedWithdrawalEvent.RemoteToken != withdrawal.TokenPair.RemoteTokenAddress {
processLog.Crit("bridge finalization fields mismatch with initiated fields!", "tx_withdrawal_hash", withdrawal.TransactionWithdrawalHash, "cross_domain_message_hash", withdrawal.CrossDomainMessageHash)
}
}
......
......@@ -10,7 +10,6 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
......@@ -160,7 +159,7 @@ func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2
}
// forward along contract events to standard bridge processor
err = l2ProcessContractEventsStandardBridge(processLog, db, ethClient, processedContractEvents)
err = l2ProcessContractEventsStandardBridge(processLog, db, processedContractEvents)
if err != nil {
return err
}
......@@ -198,10 +197,9 @@ func l2ProcessContractEventsBridgeTransactions(processLog log.Logger, db *databa
if len(withdrawalEvent.Data) == 0 && withdrawalEvent.Value.BitLen() > 0 {
ethWithdrawals = append(ethWithdrawals, &database.L2BridgeWithdrawal{
TransactionWithdrawalHash: withdrawalEvent.WithdrawalHash,
Tx: transactionWithdrawals[i].Tx,
TokenPair: database.TokenPair{
L1TokenAddress: predeploys.LegacyERC20ETHAddr,
L2TokenAddress: predeploys.LegacyERC20ETHAddr,
BridgeTransfer: database.BridgeTransfer{
Tx: transactionWithdrawals[i].Tx,
TokenPair: database.ETHTokenPair,
},
})
}
......@@ -258,8 +256,8 @@ func l2ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
sentMessages[i] = &database.L2BridgeMessage{
TransactionWithdrawalHash: msgPassedEvent.WithdrawalHash,
BridgeMessage: database.BridgeMessage{
Nonce: database.U256{Int: sentMessageEvent.MessageNonce},
MessageHash: sentMessageEvent.MessageHash,
Nonce: database.U256{Int: sentMessageEvent.MessageNonce},
SentMessageEventGUID: sentMessageEvent.Event.GUID,
GasLimit: database.U256{Int: sentMessageEvent.GasLimit},
Tx: database.Transaction{
......@@ -298,7 +296,7 @@ func l2ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
}
for _, relayedMessage := range relayedMessageEvents {
message, err := db.BridgeMessages.L1BridgeMessageByHash(relayedMessage.MsgHash)
message, err := db.BridgeMessages.L1BridgeMessage(relayedMessage.MsgHash)
if err != nil {
return err
}
......@@ -330,9 +328,7 @@ func l2ProcessContractEventsBridgeCrossDomainMessages(processLog log.Logger, db
return nil
}
func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.DB, ethClient node.EthClient, events *ProcessedContractEvents) error {
rawEthClient := ethclient.NewClient(ethClient.RawRpcClient())
func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.DB, events *ProcessedContractEvents) error {
l2ToL1MessagePasserABI, err := bindings.NewL2ToL1MessagePasser(common.Address{}, nil)
if err != nil {
return err
......@@ -357,14 +353,16 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
withdrawals[i] = &database.L2BridgeWithdrawal{
TransactionWithdrawalHash: msgPassedEvent.WithdrawalHash,
CrossDomainMessengerNonce: &database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce},
TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From,
ToAddress: initiatedBridgeEvent.To,
Amount: database.U256{Int: initiatedBridgeEvent.Amount},
Data: initiatedBridgeEvent.ExtraData,
Timestamp: initiatedBridgeEvent.Event.Timestamp,
BridgeTransfer: database.BridgeTransfer{
CrossDomainMessageHash: &initiatedBridgeEvent.CrossDomainMessageHash,
TokenPair: database.TokenPair{LocalTokenAddress: initiatedBridgeEvent.LocalToken, RemoteTokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From,
ToAddress: initiatedBridgeEvent.To,
Amount: database.U256{Int: initiatedBridgeEvent.Amount},
Data: initiatedBridgeEvent.ExtraData,
Timestamp: initiatedBridgeEvent.Event.Timestamp,
},
},
}
}
......@@ -382,26 +380,26 @@ func l2ProcessContractEventsStandardBridge(processLog log.Logger, db *database.D
// bridge transaction & messages that have a tracked lifecyle. We simply walk through and ensure
// that the corresponding initiated deposits exist as an integrity check
finalizedDepositEvents, err := StandardBridgeFinalizedEvents(rawEthClient, events)
finalizedDepositEvents, err := StandardBridgeFinalizedEvents(events)
if err != nil {
return err
}
for _, finalizedDepositEvent := range finalizedDepositEvents {
deposit, err := db.BridgeTransfers.L1BridgeDepositByCrossDomainMessengerNonce(finalizedDepositEvent.CrossDomainMessengerNonce)
deposit, err := db.BridgeTransfers.L1BridgeDepositWithFilter(database.BridgeTransfer{CrossDomainMessageHash: &finalizedDepositEvent.CrossDomainMessageHash})
if err != nil {
return err
} else if deposit == nil {
// Indexed CrossDomainMessenger messages ensure we're in a caught up state here
processLog.Error("missing indexed L1StandardBridge deposit on finalization", "cross_domain_messenger_nonce", finalizedDepositEvent.CrossDomainMessengerNonce)
processLog.Error("missing indexed L1StandardBridge deposit on finalization", "cross_domain_massage_hash", finalizedDepositEvent.CrossDomainMessageHash)
return errors.New("missing indexed L1StandardBridge deposit on finalization")
}
// sanity check on the bridge fields
if finalizedDepositEvent.From != deposit.Tx.FromAddress || finalizedDepositEvent.To != deposit.Tx.ToAddress ||
finalizedDepositEvent.Amount.Cmp(deposit.Tx.Amount.Int) != 0 || !bytes.Equal(finalizedDepositEvent.ExtraData, deposit.Tx.Data) ||
finalizedDepositEvent.LocalToken != deposit.TokenPair.L1TokenAddress || finalizedDepositEvent.RemoteToken != deposit.TokenPair.L2TokenAddress {
processLog.Error("bridge finalization fields mismatch with initiated fields!", "tx_source_hash", deposit.TransactionSourceHash, "cross_domain_messenger_nonce", deposit.CrossDomainMessengerNonce.Int)
finalizedDepositEvent.LocalToken != deposit.TokenPair.LocalTokenAddress || finalizedDepositEvent.RemoteToken != deposit.TokenPair.RemoteTokenAddress {
processLog.Error("bridge finalization fields mismatch with initiated fields!", "tx_source_hash", deposit.TransactionSourceHash, "cross_domain_message_hash", deposit.CrossDomainMessageHash)
return errors.New("bridge tx mismatch")
}
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -643,10 +643,11 @@ SequencerFeeVault_Test:test_withdraw_toL1_succeeds() (gas: 171357)
SetPrevBaseFee_Test:test_setPrevBaseFee_succeeds() (gas: 11549)
StandardBridge_Stateless_Test:test_isCorrectTokenPair_succeeds() (gas: 49936)
StandardBridge_Stateless_Test:test_isOptimismMintableERC20_succeeds() (gas: 33072)
SystemConfig_Initialize_Test:test_initialize_startBlockOverride_succeeds() (gas: 55905)
SystemConfig_Initialize_Test:test_initialize_events_succeeds() (gas: 72059)
SystemConfig_Initialize_Test:test_initialize_startBlockOverride_succeeds() (gas: 65240)
SystemConfig_Initialize_Test:test_initialize_values_succeeds() (gas: 64946)
SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 94515)
SystemConfig_Initialize_TestFail:test_initialize_startBlock_reverts() (gas: 64676)
SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 55653)
SystemConfig_Initialize_TestFail:test_initialize_startBlock_reverts() (gas: 78350)
SystemConfig_Setters_TestFail:test_setBatcherHash_notOwner_reverts() (gas: 15607)
SystemConfig_Setters_TestFail:test_setGasConfig_notOwner_reverts() (gas: 15577)
SystemConfig_Setters_TestFail:test_setGasLimit_notOwner_reverts() (gas: 15676)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -16,7 +16,7 @@
"prebuild": "./scripts/verify-foundry-install.sh",
"build:differential": "go build -o ./scripts/differential-testing/differential-testing ./scripts/differential-testing",
"build:fuzz": "(cd test-case-generator && go build ./cmd/fuzz.go)",
"autogen:invariant-docs": "tsx scripts/invariant-doc-gen.ts",
"autogen:invariant-docs": "npx tsx scripts/invariant-doc-gen.ts",
"test": "pnpm build:differential && pnpm build:fuzz && forge test",
"coverage": "pnpm build:differential && pnpm build:fuzz && forge coverage",
"coverage:lcov": "pnpm build:differential && pnpm build:fuzz && forge coverage --report lcov",
......@@ -32,7 +32,7 @@
"pre-pr": "pnpm clean && pnpm gas-snapshot && pnpm storage-snapshot && pnpm semver-lock && pnpm autogen:invariant-docs && pnpm lint && (cd ../../op-bindings && make)",
"pre-pr:full": "pnpm test && pnpm slither && pnpm validate-deploy-configs && pnpm validate-spacers && pnpm pre-pr",
"lint:ts:check": "eslint . --max-warnings=0",
"lint:forge-tests:check": "tsx scripts/forge-test-names.ts",
"lint:forge-tests:check": "npx tsx scripts/forge-test-names.ts",
"lint:contracts:check": "pnpm lint:fix && git diff --exit-code",
"lint:check": "pnpm lint:contracts:check && pnpm lint:ts:check",
"lint:ts:fix": "eslint --fix .",
......
......@@ -71,7 +71,7 @@ contract Multichain is SafeBuilder {
/// @notice OptimismPortal implementation to upgrade to
address internal constant OptimismPortalImplementation = 0x345D27c7B6C90fef5beA9631037C36119f4bF93e;
/// @notice SystemConfig implementation to upgrade to
address internal constant SystemConfigImplementation = 0x00CB689221540dEd0FA5247dbE7Fc66621F431a6;
address internal constant SystemConfigImplementation = 0x543bA4AADBAb8f9025686Bd03993043599c6fB04;
/// @notice L1ERC721Bridge implementation to upgrade to
address internal constant L1ERC721BridgeImplementation = 0x53C115eD8D9902f4999fDBd8B93Ea79BF37cb588;
......@@ -84,7 +84,7 @@ contract Multichain is SafeBuilder {
string internal constant L2OutputOracleVersion = "1.4.1";
string internal constant OptimismMintableERC20FactoryVersion = "1.1.2";
string internal constant OptimismPortalVersion = "1.8.1";
string internal constant SystemConfigVersion = "1.5.0";
string internal constant SystemConfigVersion = "1.6.0";
string internal constant L1ERC721BridgeVersion = "1.2.1";
/// @notice The value of the NETWORK env var
......
......@@ -6,7 +6,7 @@
"src/L1/L1StandardBridge.sol": "0xbd7b303cefe46bc14bf1a2b81e5702ff45ce9c5257524e59778e11c75f7f5bdc",
"src/L1/L2OutputOracle.sol": "0x05ea17a834563ffa50cade81189b120b6f0805ba316d6a9893c8cf8b231e57e3",
"src/L1/OptimismPortal.sol": "0xeefcc16d30e14ed7ce9970f3aeaf1d5668324b3fc1ddb4790da5804cfdd78980",
"src/L1/SystemConfig.sol": "0x29beec0a03b9602a53e3ceaec2354972d917f8b80f1b3a8f03f4fb7a67753fce",
"src/L1/SystemConfig.sol": "0xd5904b53153f2e32be28f2ce1ea51374b19fdf4f478f486f02cf67d8b62b7c29",
"src/L2/BaseFeeVault.sol": "0xd8df28898799b80c370e77e9aad09f79235dfda2bf13e56daf21997cfe54200d",
"src/L2/GasPriceOracle.sol": "0xb7d8c4f3ea8db31900125e341aae42a862a2b7d3f1c1aa60c97dc2d0e022b7ba",
"src/L2/L1Block.sol": "0x38ea78a9611656a60ae4d58db75e96413a638e3ccb2e935052441f98a1fd3105",
......
......@@ -98,11 +98,11 @@ contract SystemConfig is OwnableUpgradeable, Semver {
/// @notice The block at which the op-node can start searching for logs from.
uint256 public startBlock;
/// @custom:semver 1.5.0
/// @custom:semver 1.6.0
/// @notice Constructs the SystemConfig contract. Cannot set
/// the owner to `address(0)` due to the Ownable contract's
/// implementation, so set it to `address(0xdEaD)`
constructor() Semver(1, 5, 0) {
constructor() Semver(1, 6, 0) {
initialize({
_owner: address(0xdEaD),
_overhead: 0,
......@@ -165,12 +165,12 @@ contract SystemConfig is OwnableUpgradeable, Semver {
__Ownable_init();
transferOwnership(_owner);
overhead = _overhead;
scalar = _scalar;
batcherHash = _batcherHash;
gasLimit = _gasLimit;
// These are set in ascending order of their UpdateTypes.
_setBatcherHash(_batcherHash);
_setGasConfig({ _overhead: _overhead, _scalar: _scalar });
_setGasLimit(_gasLimit);
_setUnsafeBlockSigner(_unsafeBlockSigner);
_setAddress(_unsafeBlockSigner, UNSAFE_BLOCK_SIGNER_SLOT);
_setAddress(_batchInbox, BATCH_INBOX_SLOT);
_setAddress(_addresses.l1CrossDomainMessenger, L1_CROSS_DOMAIN_MESSENGER_SLOT);
_setAddress(_addresses.l1ERC721Bridge, L1_ERC_721_BRIDGE_SLOT);
......@@ -282,28 +282,47 @@ contract SystemConfig is OwnableUpgradeable, Semver {
}
}
/// @notice Updates the unsafe block signer address.
/// @notice Updates the unsafe block signer address. Can only be called by the owner.
/// @param _unsafeBlockSigner New unsafe block signer address.
function setUnsafeBlockSigner(address _unsafeBlockSigner) external onlyOwner {
_setUnsafeBlockSigner(_unsafeBlockSigner);
}
/// @notice Updates the unsafe block signer address.
/// @param _unsafeBlockSigner New unsafe block signer address.
function _setUnsafeBlockSigner(address _unsafeBlockSigner) internal {
_setAddress(_unsafeBlockSigner, UNSAFE_BLOCK_SIGNER_SLOT);
bytes memory data = abi.encode(_unsafeBlockSigner);
emit ConfigUpdate(VERSION, UpdateType.UNSAFE_BLOCK_SIGNER, data);
}
/// @notice Updates the batcher hash.
/// @notice Updates the batcher hash. Can only be called by the owner.
/// @param _batcherHash New batcher hash.
function setBatcherHash(bytes32 _batcherHash) external onlyOwner {
_setBatcherHash(_batcherHash);
}
/// @notice Internal function for updating the batcher hash.
/// @param _batcherHash New batcher hash.
function _setBatcherHash(bytes32 _batcherHash) internal {
batcherHash = _batcherHash;
bytes memory data = abi.encode(_batcherHash);
emit ConfigUpdate(VERSION, UpdateType.BATCHER, data);
}
/// @notice Updates gas config.
/// @notice Updates gas config. Can only be called by the owner.
/// @param _overhead New overhead value.
/// @param _scalar New scalar value.
function setGasConfig(uint256 _overhead, uint256 _scalar) external onlyOwner {
_setGasConfig(_overhead, _scalar);
}
/// @notice Internal function for updating the gas config.
/// @param _overhead New overhead value.
/// @param _scalar New scalar value.
function _setGasConfig(uint256 _overhead, uint256 _scalar) internal {
overhead = _overhead;
scalar = _scalar;
......@@ -311,9 +330,15 @@ contract SystemConfig is OwnableUpgradeable, Semver {
emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data);
}
/// @notice Updates the L2 gas limit.
/// @notice Updates the L2 gas limit. Can only be called by the owner.
/// @param _gasLimit New gas limit.
function setGasLimit(uint64 _gasLimit) external onlyOwner {
_setGasLimit(_gasLimit);
}
/// @notice Internal function for updating the L2 gas limit.
/// @param _gasLimit New gas limit.
function _setGasLimit(uint64 _gasLimit) internal {
require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
gasLimit = _gasLimit;
......
......@@ -51,6 +51,9 @@ contract CommonTest is Test {
event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData);
/// @dev OpenZeppelin Ownable.sol transferOwnership event
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
FFIInterface ffi;
function setUp() public virtual {
......
......@@ -26,9 +26,6 @@ contract XDomainSetter3 is CrossDomainOwnable3 {
contract CrossDomainOwnable3_Test is Messenger_Initializer {
XDomainSetter3 setter;
/// @dev OpenZeppelin Ownable.sol transferOwnership event
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/// @dev CrossDomainOwnable3.sol transferOwnership event
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner, bool isLocal);
......
......@@ -18,6 +18,8 @@ contract SystemConfig_Init is CommonTest {
SystemConfig sysConf;
SystemConfig systemConfigImpl;
event ConfigUpdate(uint256 indexed version, SystemConfig.UpdateType indexed updateType, bytes data);
// Dummy addresses used to test getters
address constant batchInbox = address(0x18);
address constant l1CrossDomainMessenger = address(0x20);
......@@ -138,6 +140,51 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init {
);
assertEq(sysConf.startBlock(), startBlock);
}
/// @dev Ensures that the events are emitted during initialization.
function test_initialize_events_succeeds() external {
// Wipe out the initialized slot so the proxy can be initialized again
vm.store(address(sysConf), bytes32(0), bytes32(0));
vm.store(address(sysConf), bytes32(uint256(106)), bytes32(0));
assertEq(sysConf.startBlock(), 0);
// The order depends here
vm.expectEmit(true, true, true, true, address(sysConf));
emit ConfigUpdate(0, SystemConfig.UpdateType.BATCHER, abi.encode(batcherHash));
vm.expectEmit(true, true, true, true, address(sysConf));
emit ConfigUpdate(0, SystemConfig.UpdateType.GAS_CONFIG, abi.encode(overhead, scalar));
vm.expectEmit(true, true, true, true, address(sysConf));
emit ConfigUpdate(0, SystemConfig.UpdateType.GAS_LIMIT, abi.encode(gasLimit));
vm.expectEmit(true, true, true, true, address(sysConf));
emit ConfigUpdate(0, SystemConfig.UpdateType.UNSAFE_BLOCK_SIGNER, abi.encode(unsafeBlockSigner));
vm.prank(multisig);
Proxy(payable(address(sysConf))).upgradeToAndCall(
address(systemConfigImpl),
abi.encodeCall(
SystemConfig.initialize,
(
alice, // _owner,
overhead, // _overhead,
scalar, // _scalar,
batcherHash, // _batcherHash
gasLimit, // _gasLimit,
unsafeBlockSigner, // _unsafeBlockSigner,
Constants.DEFAULT_RESOURCE_CONFIG(), // _config,
0, // _startBlock
batchInbox, // _batchInbox
SystemConfig.Addresses({ // _addresses
l1CrossDomainMessenger: l1CrossDomainMessenger,
l1ERC721Bridge: l1ERC721Bridge,
l1StandardBridge: l1StandardBridge,
l2OutputOracle: l2OutputOracle,
optimismPortal: optimismPortal,
optimismMintableERC20Factory: optimismMintableERC20Factory
})
)
)
);
}
}
contract SystemConfig_Initialize_TestFail is SystemConfig_Init {
......@@ -318,8 +365,6 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
}
contract SystemConfig_Setters_Test is SystemConfig_Init {
event ConfigUpdate(uint256 indexed version, SystemConfig.UpdateType indexed updateType, bytes data);
/// @dev Tests that `setBatcherHash` updates the batcher hash successfully.
function testFuzz_setBatcherHash_succeeds(bytes32 newBatcherHash) external {
vm.expectEmit(true, true, true, true);
......
......@@ -11,5 +11,7 @@ ignores: [
"eslint-plugin-prettier",
"chai",
"ts-node",
"typedoc"
"typedoc",
"ethereum-waffle",
"nyc"
]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment