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

Merge branch 'develop' into dependabot/go_modules/golang.org/x/crypto-0.12.0

parents 9339ed7a 1403c7d7
---
'@eth-optimism/fee-estimation': patch
---
Fixed bug with 'estimateFees' not taking into account the l2 gas price
...@@ -16,17 +16,15 @@ type PaginationResponse struct { ...@@ -16,17 +16,15 @@ type PaginationResponse struct {
HasNextPage bool `json:"hasNextPage"` HasNextPage bool `json:"hasNextPage"`
} }
func (a *Api) DepositsHandler(w http.ResponseWriter, r *http.Request) { func (a *Api) L1DepositsHandler(w http.ResponseWriter, r *http.Request) {
bv := a.bridgeView bv := a.BridgeTransfersView
address := common.HexToAddress(chi.URLParam(r, "address")) address := common.HexToAddress(chi.URLParam(r, "address"))
// limit := getIntFromQuery(r, "limit", 10) // limit := getIntFromQuery(r, "limit", 10)
// cursor := r.URL.Query().Get("cursor") // cursor := r.URL.Query().Get("cursor")
// sortDirection := r.URL.Query().Get("sortDirection") // sortDirection := r.URL.Query().Get("sortDirection")
deposits, err := bv.DepositsByAddress(address) deposits, err := bv.L1BridgeDepositsByAddress(address)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
...@@ -43,17 +41,15 @@ func (a *Api) DepositsHandler(w http.ResponseWriter, r *http.Request) { ...@@ -43,17 +41,15 @@ func (a *Api) DepositsHandler(w http.ResponseWriter, r *http.Request) {
jsonResponse(w, response, http.StatusOK) jsonResponse(w, response, http.StatusOK)
} }
func (a *Api) WithdrawalsHandler(w http.ResponseWriter, r *http.Request) { func (a *Api) L2WithdrawalsHandler(w http.ResponseWriter, r *http.Request) {
bv := a.bridgeView bv := a.BridgeTransfersView
address := common.HexToAddress(chi.URLParam(r, "address")) address := common.HexToAddress(chi.URLParam(r, "address"))
// limit := getIntFromQuery(r, "limit", 10) // limit := getIntFromQuery(r, "limit", 10)
// cursor := r.URL.Query().Get("cursor") // cursor := r.URL.Query().Get("cursor")
// sortDirection := r.URL.Query().Get("sortDirection") // sortDirection := r.URL.Query().Get("sortDirection")
withdrawals, err := bv.WithdrawalsByAddress(address) withdrawals, err := bv.L2BridgeWithdrawalsByAddress(address)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
...@@ -83,22 +79,20 @@ func jsonResponse(w http.ResponseWriter, data interface{}, statusCode int) { ...@@ -83,22 +79,20 @@ func jsonResponse(w http.ResponseWriter, data interface{}, statusCode int) {
} }
type Api struct { type Api struct {
Router *chi.Mux Router *chi.Mux
bridgeView database.BridgeView BridgeTransfersView database.BridgeTransfersView
} }
func NewApi(bv database.BridgeView) *Api { func NewApi(bv database.BridgeTransfersView) *Api {
r := chi.NewRouter() r := chi.NewRouter()
api := &Api{ api := &Api{Router: r, BridgeTransfersView: bv}
Router: r,
bridgeView: bv,
}
// these regex are .+ because I wasn't sure what they should be // these regex are .+ because I wasn't sure what they should be
// don't want a regex for addresses because would prefer to validate the address // don't want a regex for addresses because would prefer to validate the address
// with go-ethereum and throw a friendly error message // with go-ethereum and throw a friendly error message
r.Get("/api/v0/deposits/{address:.+}", api.DepositsHandler) r.Get("/api/v0/deposits/{address:.+}", api.L1DepositsHandler)
r.Get("/api/v0/withdrawals/{address:.+}", api.WithdrawalsHandler) r.Get("/api/v0/withdrawals/{address:.+}", api.L2WithdrawalsHandler)
r.Get("/healthz", api.HealthzHandler) r.Get("/healthz", api.HealthzHandler)
return api return api
......
...@@ -12,89 +12,67 @@ import ( ...@@ -12,89 +12,67 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// MockBridgeView mocks the BridgeView interface // MockBridgeTransfersView mocks the BridgeTransfersView interface
type MockBridgeView struct{} type MockBridgeTransfersView struct{}
const ( const (
guid1 = "8408b6d2-7c90-4cfc-8604-b2204116cb6a" guid1 = "8408b6d2-7c90-4cfc-8604-b2204116cb6a"
guid2 = "8408b6d2-7c90-4cfc-8604-b2204116cb6b" guid2 = "8408b6d2-7c90-4cfc-8604-b2204116cb6b"
) )
// DepositsByAddress mocks returning deposits by an address var (
func (mbv *MockBridgeView) DepositsByAddress(address common.Address) ([]*database.DepositWithTransactionHashes, error) { deposit = database.L1BridgeDeposit{
return []*database.DepositWithTransactionHashes{
{
Deposit: database.Deposit{
GUID: uuid.MustParse(guid1),
InitiatedL1EventGUID: uuid.MustParse(guid2),
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
},
L1TransactionHash: common.HexToHash("0x123"),
},
}, nil
}
// DepositsByAddress mocks returning deposits by an address
func (mbv *MockBridgeView) DepositByMessageNonce(nonce *big.Int) (*database.Deposit, error) {
return &database.Deposit{
GUID: uuid.MustParse(guid1), GUID: uuid.MustParse(guid1),
InitiatedL1EventGUID: uuid.MustParse(guid2), InitiatedL1EventGUID: uuid.MustParse(guid2),
Tx: database.Transaction{}, Tx: database.Transaction{},
TokenPair: database.TokenPair{}, TokenPair: database.TokenPair{},
}, nil }
withdrawal = database.L2BridgeWithdrawal{
GUID: uuid.MustParse(guid2),
InitiatedL2EventGUID: uuid.MustParse(guid1),
WithdrawalHash: common.HexToHash("0x456"),
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
}
)
func (mbv *MockBridgeTransfersView) L1BridgeDeposit(hash common.Hash) (*database.L1BridgeDeposit, error) {
return &deposit, nil
} }
// LatestDepositMessageNonce mocks returning the latest cross domain message nonce for a deposit func (mbv *MockBridgeTransfersView) L1BridgeDepositByCrossDomainMessengerNonce(nonce *big.Int) (*database.L1BridgeDeposit, error) {
func (mbv *MockBridgeView) LatestDepositMessageNonce() (*big.Int, error) { return &deposit, nil
return big.NewInt(0), nil
} }
// WithdrawalsByAddress mocks returning withdrawals by an address func (mbv *MockBridgeTransfersView) L1BridgeDepositsByAddress(address common.Address) ([]*database.L1BridgeDepositWithTransactionHashes, error) {
func (mbv *MockBridgeView) WithdrawalsByAddress(address common.Address) ([]*database.WithdrawalWithTransactionHashes, error) { return []*database.L1BridgeDepositWithTransactionHashes{
return []*database.WithdrawalWithTransactionHashes{
{ {
Withdrawal: database.Withdrawal{ L1BridgeDeposit: deposit,
GUID: uuid.MustParse(guid2), L1TransactionHash: common.HexToHash("0x123"),
InitiatedL2EventGUID: uuid.MustParse(guid1),
WithdrawalHash: common.HexToHash("0x456"),
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
},
L2TransactionHash: common.HexToHash("0x789"),
}, },
}, nil }, nil
} }
// WithdrawalsByMessageNonce mocks returning withdrawals by a withdrawal hash func (mbv *MockBridgeTransfersView) L2BridgeWithdrawalByWithdrawalHash(address common.Hash) (*database.L2BridgeWithdrawal, error) {
func (mbv *MockBridgeView) WithdrawalByMessageNonce(nonce *big.Int) (*database.Withdrawal, error) { return &withdrawal, nil
return &database.Withdrawal{
GUID: uuid.MustParse(guid2),
InitiatedL2EventGUID: uuid.MustParse(guid1),
WithdrawalHash: common.HexToHash("0x456"),
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
}, nil
} }
// WithdrawalsByHash mocks returning withdrawals by a withdrawal hash func (mbv *MockBridgeTransfersView) L2BridgeWithdrawalByCrossDomainMessengerNonce(nonce *big.Int) (*database.L2BridgeWithdrawal, error) {
func (mbv *MockBridgeView) WithdrawalByHash(address common.Hash) (*database.Withdrawal, error) { return &withdrawal, nil
return &database.Withdrawal{
GUID: uuid.MustParse(guid2),
InitiatedL2EventGUID: uuid.MustParse(guid1),
WithdrawalHash: common.HexToHash("0x456"),
Tx: database.Transaction{},
TokenPair: database.TokenPair{},
}, nil
} }
// LatestWithdrawalMessageNonce mocks returning the latest cross domain message nonce for a withdrawal func (mbv *MockBridgeTransfersView) L2BridgeWithdrawalsByAddress(address common.Address) ([]*database.L2BridgeWithdrawalWithTransactionHashes, error) {
func (mbv *MockBridgeView) LatestWithdrawalMessageNonce() (*big.Int, error) { return []*database.L2BridgeWithdrawalWithTransactionHashes{
return big.NewInt(0), nil {
L2BridgeWithdrawal: withdrawal,
L2TransactionHash: common.HexToHash("0x789"),
},
}, nil
} }
func TestHealthz(t *testing.T) { func TestHealthz(t *testing.T) {
api := NewApi(&MockBridgeView{}) api := NewApi(&MockBridgeTransfersView{})
request, err := http.NewRequest("GET", "/healthz", nil) request, err := http.NewRequest("GET", "/healthz", nil)
assert.Nil(t, err) assert.Nil(t, err)
...@@ -104,8 +82,8 @@ func TestHealthz(t *testing.T) { ...@@ -104,8 +82,8 @@ func TestHealthz(t *testing.T) {
assert.Equal(t, http.StatusOK, responseRecorder.Code) assert.Equal(t, http.StatusOK, responseRecorder.Code)
} }
func TestDepositsHandler(t *testing.T) { func TestL1BridgeDepositsHandler(t *testing.T) {
api := NewApi(&MockBridgeView{}) api := NewApi(&MockBridgeTransfersView{})
request, err := http.NewRequest("GET", "/api/v0/deposits/0x123", nil) request, err := http.NewRequest("GET", "/api/v0/deposits/0x123", nil)
assert.Nil(t, err) assert.Nil(t, err)
...@@ -115,8 +93,8 @@ func TestDepositsHandler(t *testing.T) { ...@@ -115,8 +93,8 @@ func TestDepositsHandler(t *testing.T) {
assert.Equal(t, http.StatusOK, responseRecorder.Code) assert.Equal(t, http.StatusOK, responseRecorder.Code)
} }
func TestWithdrawalsHandler(t *testing.T) { func TestL2BridgeWithdrawalsByAddressHandler(t *testing.T) {
api := NewApi(&MockBridgeView{}) api := NewApi(&MockBridgeTransfersView{})
request, err := http.NewRequest("GET", "/api/v0/withdrawals/0x123", nil) request, err := http.NewRequest("GET", "/api/v0/withdrawals/0x123", nil)
assert.Nil(t, err) assert.Nil(t, err)
......
...@@ -10,9 +10,9 @@ import ( ...@@ -10,9 +10,9 @@ import (
type DB struct { type DB struct {
gorm *gorm.DB gorm *gorm.DB
Blocks BlocksDB Blocks BlocksDB
ContractEvents ContractEventsDB ContractEvents ContractEventsDB
Bridge BridgeDB BridgeTransfers BridgeTransfersDB
} }
func NewDB(dsn string) (*DB, error) { func NewDB(dsn string) (*DB, error) {
...@@ -31,10 +31,10 @@ func NewDB(dsn string) (*DB, error) { ...@@ -31,10 +31,10 @@ func NewDB(dsn string) (*DB, error) {
} }
db := &DB{ db := &DB{
gorm: gorm, gorm: gorm,
Blocks: newBlocksDB(gorm), Blocks: newBlocksDB(gorm),
ContractEvents: newContractEventsDB(gorm), ContractEvents: newContractEventsDB(gorm),
Bridge: newBridgeDB(gorm), BridgeTransfers: newBridgeTransfersDB(gorm),
} }
return db, nil return db, nil
...@@ -59,9 +59,9 @@ func (db *DB) Close() error { ...@@ -59,9 +59,9 @@ func (db *DB) Close() error {
func dbFromGormTx(tx *gorm.DB) *DB { func dbFromGormTx(tx *gorm.DB) *DB {
return &DB{ return &DB{
gorm: tx, gorm: tx,
Blocks: newBlocksDB(tx), Blocks: newBlocksDB(tx),
ContractEvents: newContractEventsDB(tx), ContractEvents: newContractEventsDB(tx),
Bridge: newBridgeDB(tx), BridgeTransfers: newBridgeTransfersDB(tx),
} }
} }
package e2e_tests
import (
"context"
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/indexer/processor"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
func TestE2EBridge(t *testing.T) {
testSuite := createE2ETestSuite(t)
l1Client := testSuite.OpSys.Clients["l1"]
l2Client := testSuite.OpSys.Clients["sequencer"]
l1StandardBridge, err := bindings.NewL1StandardBridge(testSuite.OpCfg.L1Deployments.L1StandardBridgeProxy, l1Client)
require.NoError(t, err)
l2StandardBridge, err := bindings.NewL2StandardBridge(predeploys.L2StandardBridgeAddr, l2Client)
require.NoError(t, err)
// pre-emptively conduct a deposit & withdrawal to speed up the test
setupCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
aliceAddr := testSuite.OpCfg.Secrets.Addresses().Alice
l1Opts, err := bind.NewKeyedTransactorWithChainID(testSuite.OpCfg.Secrets.Alice, testSuite.OpCfg.L1ChainIDBig())
require.NoError(t, err)
l2Opts, err := bind.NewKeyedTransactorWithChainID(testSuite.OpCfg.Secrets.Alice, testSuite.OpCfg.L2ChainIDBig())
require.NoError(t, err)
l1Opts.Value = big.NewInt(params.Ether)
l2Opts.Value = big.NewInt(params.Ether)
depositTx, err := l1StandardBridge.DepositETH(l1Opts, 200_000, []byte{byte(1)})
require.NoError(t, err)
withdrawTx, err := l2StandardBridge.Withdraw(l2Opts, processor.EthAddress, big.NewInt(params.Ether), 200_000, []byte{byte(1)})
require.NoError(t, err)
depositReceipt, err := utils.WaitReceiptOK(setupCtx, l1Client, depositTx.Hash())
require.NoError(t, err)
withdrawalReceipt, err := utils.WaitReceiptOK(setupCtx, l2Client, withdrawTx.Hash())
require.NoError(t, err)
t.Run("indexes ETH deposits", func(t *testing.T) {
testCtx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
// Pause the L2Processor so that we can test for finalization separately. A pause is
// required since deposit inclusion is apart of the L2 block derivation process
testSuite.Indexer.L2Processor.PauseForTest()
// (1) Test Deposit Initiation
// wait for processor catchup
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader()
return l1Header != nil && l1Header.Number.Uint64() >= depositReceipt.BlockNumber.Uint64(), nil
}))
aliceDeposits, err := testSuite.DB.Bridge.DepositsByAddress(aliceAddr)
require.NoError(t, err)
require.Len(t, aliceDeposits, 1)
require.Equal(t, depositTx.Hash(), aliceDeposits[0].L1TransactionHash)
require.Empty(t, aliceDeposits[0].FinalizedL2TransactionHash)
deposit := aliceDeposits[0].Deposit
require.Nil(t, deposit.FinalizedL2EventGUID)
require.Equal(t, processor.EthAddress, deposit.TokenPair.L1TokenAddress)
require.Equal(t, processor.EthAddress, deposit.TokenPair.L2TokenAddress)
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.Equal(t, byte(1), deposit.Tx.Data[0])
// (2) Test Deposit Finalization
testSuite.Indexer.L2Processor.ResumeForTest()
// finalization hash can be deterministically derived from TransactionDeposited log
var depositTxHash common.Hash
for _, log := range depositReceipt.Logs {
if log.Topics[0] == derive.DepositEventABIHash {
deposit, err := derive.UnmarshalDepositLogEvent(log)
require.NoError(t, err)
depositTxHash = types.NewTx(deposit).Hash()
break
}
}
// wait for the l2 processor to catch this deposit in the derivation process
_, err = utils.WaitReceiptOK(testCtx, l2Client, depositTxHash)
require.NoError(t, err)
l2Height, err := l2Client.BlockNumber(testCtx)
require.NoError(t, err)
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l2Header := testSuite.Indexer.L2Processor.LatestProcessedHeader()
return l2Header != nil && l2Header.Number.Uint64() >= l2Height, nil
}))
aliceDeposits, err = testSuite.DB.Bridge.DepositsByAddress(aliceAddr)
require.NoError(t, err)
require.Equal(t, depositTxHash, aliceDeposits[0].FinalizedL2TransactionHash)
require.NotNil(t, aliceDeposits[0].Deposit.FinalizedL2EventGUID)
})
t.Run("indexes ETH withdrawals", func(t *testing.T) {
testCtx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
// (1) Test Withdrawal Initiation
// wait for processor catchup
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l2Header := testSuite.Indexer.L2Processor.LatestProcessedHeader()
return l2Header != nil && l2Header.Number.Uint64() >= withdrawalReceipt.BlockNumber.Uint64(), nil
}))
aliceWithdrawals, err := testSuite.DB.Bridge.WithdrawalsByAddress(aliceAddr)
require.NoError(t, err)
require.Len(t, aliceWithdrawals, 1)
require.Equal(t, withdrawTx.Hash(), aliceWithdrawals[0].L2TransactionHash)
require.Empty(t, aliceWithdrawals[0].ProvenL1TransactionHash)
require.Empty(t, aliceWithdrawals[0].FinalizedL1TransactionHash)
withdrawal := aliceWithdrawals[0].Withdrawal
require.Nil(t, withdrawal.ProvenL1EventGUID)
require.Nil(t, withdrawal.FinalizedL1EventGUID)
require.Equal(t, processor.EthAddress, withdrawal.TokenPair.L1TokenAddress)
require.Equal(t, processor.EthAddress, withdrawal.TokenPair.L2TokenAddress)
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.Equal(t, byte(1), withdrawal.Tx.Data[0])
// (2) Test Withdrawal Proven
// prove & wait for processor catchup
withdrawParams, proveReceipt := op_e2e.ProveWithdrawal(t, *testSuite.OpCfg, l1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawalReceipt)
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader()
return l1Header != nil && l1Header.Number.Uint64() >= proveReceipt.BlockNumber.Uint64(), nil
}))
aliceWithdrawals, err = testSuite.DB.Bridge.WithdrawalsByAddress(aliceAddr)
require.NoError(t, err)
require.Empty(t, aliceWithdrawals[0].FinalizedL1TransactionHash)
require.Equal(t, proveReceipt.TxHash, aliceWithdrawals[0].ProvenL1TransactionHash)
// (3) Test Withdrawal Finalization
// finalize & wait for processor catchup
finalizeReceipt := op_e2e.FinalizeWithdrawal(t, *testSuite.OpCfg, l1Client, testSuite.OpCfg.Secrets.Alice, proveReceipt, withdrawParams)
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader()
return l1Header != nil && l1Header.Number.Uint64() >= finalizeReceipt.BlockNumber.Uint64(), nil
}))
aliceWithdrawals, err = testSuite.DB.Bridge.WithdrawalsByAddress(aliceAddr)
require.NoError(t, err)
require.Equal(t, finalizeReceipt.TxHash, aliceWithdrawals[0].FinalizedL1TransactionHash)
})
}
...@@ -23,9 +23,7 @@ import ( ...@@ -23,9 +23,7 @@ import (
func TestE2EBlockHeaders(t *testing.T) { func TestE2EBlockHeaders(t *testing.T) {
testSuite := createE2ETestSuite(t) testSuite := createE2ETestSuite(t)
l1Client := testSuite.OpSys.Clients["l1"] l2OutputOracle, err := bindings.NewL2OutputOracle(testSuite.OpCfg.L1Deployments.L2OutputOracleProxy, testSuite.L1Client)
l2Client := testSuite.OpSys.Clients["sequencer"]
l2OutputOracle, err := bindings.NewL2OutputOracleCaller(testSuite.OpCfg.L1Deployments.L2OutputOracleProxy, l1Client)
require.NoError(t, err) require.NoError(t, err)
// a minute for total setup to finish // a minute for total setup to finish
...@@ -39,7 +37,7 @@ func TestE2EBlockHeaders(t *testing.T) { ...@@ -39,7 +37,7 @@ func TestE2EBlockHeaders(t *testing.T) {
})) }))
// ensure the processors are caught up to this state // ensure the processors are caught up to this state
l1Height, err := l1Client.BlockNumber(setupCtx) l1Height, err := testSuite.L1Client.BlockNumber(setupCtx)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, utils.WaitFor(setupCtx, time.Second, func() (bool, error) { require.NoError(t, utils.WaitFor(setupCtx, time.Second, func() (bool, error) {
l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader() l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader()
...@@ -60,7 +58,7 @@ func TestE2EBlockHeaders(t *testing.T) { ...@@ -60,7 +58,7 @@ func TestE2EBlockHeaders(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, indexedHeader) require.NotNil(t, indexedHeader)
header, err := l2Client.HeaderByNumber(context.Background(), height) header, err := testSuite.L2Client.HeaderByNumber(context.Background(), height)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, indexedHeader) require.NotNil(t, indexedHeader)
...@@ -93,7 +91,7 @@ func TestE2EBlockHeaders(t *testing.T) { ...@@ -93,7 +91,7 @@ func TestE2EBlockHeaders(t *testing.T) {
require.NotEmpty(t, output.L1ContractEventGUID) require.NotEmpty(t, output.L1ContractEventGUID)
// we may as well check the integrity of the output root // we may as well check the integrity of the output root
l2Block, err := l2Client.BlockByNumber(context.Background(), blockNumber) l2Block, err := testSuite.L2Client.BlockByNumber(context.Background(), blockNumber)
require.NoError(t, err) require.NoError(t, err)
messagePasserStorageHash, err := l2EthClient.StorageHash(predeploys.L2ToL1MessagePasserAddr, blockNumber) messagePasserStorageHash, err := l2EthClient.StorageHash(predeploys.L2ToL1MessagePasserAddr, blockNumber)
require.NoError(t, err) require.NoError(t, err)
...@@ -111,12 +109,10 @@ func TestE2EBlockHeaders(t *testing.T) { ...@@ -111,12 +109,10 @@ func TestE2EBlockHeaders(t *testing.T) {
testCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) testCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
devContracts := make([]common.Address, 0) l1Contracts := []common.Address{}
testSuite.OpCfg.L1Deployments.ForEach(func(name string, address common.Address) { testSuite.OpCfg.L1Deployments.ForEach(func(name string, addr common.Address) { l1Contracts = append(l1Contracts, addr) })
devContracts = append(devContracts, address) logFilter := ethereum.FilterQuery{FromBlock: big.NewInt(0), ToBlock: big.NewInt(int64(l1Height)), Addresses: l1Contracts}
}) logs, err := testSuite.L1Client.FilterLogs(testCtx, logFilter) // []types.Log
logFilter := ethereum.FilterQuery{FromBlock: big.NewInt(0), ToBlock: big.NewInt(int64(l1Height)), Addresses: devContracts}
logs, err := l1Client.FilterLogs(testCtx, logFilter) // []types.Log
require.NoError(t, err) require.NoError(t, err)
for _, log := range logs { for _, log := range logs {
...@@ -128,7 +124,7 @@ func TestE2EBlockHeaders(t *testing.T) { ...@@ -128,7 +124,7 @@ func TestE2EBlockHeaders(t *testing.T) {
require.Equal(t, log.Index, uint(contractEvent.LogIndex)) require.Equal(t, log.Index, uint(contractEvent.LogIndex))
// ensure the block is also indexed // ensure the block is also indexed
block, err := l1Client.BlockByNumber(testCtx, big.NewInt(int64(log.BlockNumber))) block, err := testSuite.L1Client.BlockByNumber(testCtx, big.NewInt(int64(log.BlockNumber)))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, block.Time(), contractEvent.Timestamp) require.Equal(t, block.Time(), contractEvent.Timestamp)
......
package e2e_tests
import (
"context"
"math/big"
"testing"
"time"
e2etest_utils "github.com/ethereum-optimism/optimism/indexer/e2e_tests/utils"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
func TestE2EBridgeTransfersStandardBridgeETHDeposit(t *testing.T) {
testSuite := createE2ETestSuite(t)
testCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
l1StandardBridge, err := bindings.NewL1StandardBridge(testSuite.OpCfg.L1Deployments.L1StandardBridgeProxy, testSuite.L1Client)
require.NoError(t, err)
// 1 ETH transfer
aliceAddr := testSuite.OpCfg.Secrets.Addresses().Alice
l1Opts, err := bind.NewKeyedTransactorWithChainID(testSuite.OpCfg.Secrets.Alice, testSuite.OpCfg.L1ChainIDBig())
require.NoError(t, err)
l1Opts.Value = big.NewInt(params.Ether)
// Pause the L2Processor so that we can test for finalization separately. A pause is
// required since deposit inclusion is apart of the L2 block derivation process
testSuite.Indexer.L2Processor.PauseForTest()
// (1) Test Deposit Initiation
depositTx, err := l1StandardBridge.DepositETH(l1Opts, 200_000, []byte{byte(1)})
require.NoError(t, err)
depositReceipt, err := utils.WaitReceiptOK(testCtx, testSuite.L1Client, depositTx.Hash())
require.NoError(t, err)
depositInfo, err := e2etest_utils.ParseDepositInfo(depositReceipt)
require.NoError(t, err)
// wait for processor catchup
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader()
return l1Header != nil && l1Header.Number.Uint64() >= depositReceipt.BlockNumber.Uint64(), nil
}))
aliceDeposits, err := testSuite.DB.BridgeTransfers.L1BridgeDepositsByAddress(aliceAddr)
require.NoError(t, err)
require.Len(t, aliceDeposits, 1)
require.Equal(t, depositTx.Hash(), aliceDeposits[0].L1TransactionHash)
require.Empty(t, aliceDeposits[0].FinalizedL2TransactionHash)
deposit := aliceDeposits[0].L1BridgeDeposit
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.L1TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, deposit.TokenPair.L2TokenAddress)
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.Equal(t, byte(1), deposit.Tx.Data[0])
// (2) Test Deposit Finalization
require.Nil(t, deposit.FinalizedL2EventGUID)
testSuite.Indexer.L2Processor.ResumeForTest()
// wait for the l2 processor to catch this deposit in the derivation process
depositReceipt, err = utils.WaitReceiptOK(testCtx, testSuite.L2Client, types.NewTx(depositInfo.DepositTx).Hash())
require.NoError(t, err)
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l2Header := testSuite.Indexer.L2Processor.LatestProcessedHeader()
return l2Header != nil && l2Header.Number.Uint64() >= depositReceipt.BlockNumber.Uint64(), nil
}))
aliceDeposits, err = testSuite.DB.BridgeTransfers.L1BridgeDepositsByAddress(aliceAddr)
require.NoError(t, err)
require.NotNil(t, aliceDeposits[0].L1BridgeDeposit.FinalizedL2EventGUID)
require.Equal(t, types.NewTx(depositInfo.DepositTx).Hash(), aliceDeposits[0].FinalizedL2TransactionHash)
}
func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
testSuite := createE2ETestSuite(t)
testCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
optimismPortal, err := bindings.NewOptimismPortal(testSuite.OpCfg.L1Deployments.OptimismPortalProxy, testSuite.L1Client)
require.NoError(t, err)
l2StandardBridge, err := bindings.NewL2StandardBridge(predeploys.L2StandardBridgeAddr, testSuite.L2Client)
require.NoError(t, err)
// 1 ETH transfer
aliceAddr := testSuite.OpCfg.Secrets.Addresses().Alice
l2Opts, err := bind.NewKeyedTransactorWithChainID(testSuite.OpCfg.Secrets.Alice, testSuite.OpCfg.L2ChainIDBig())
require.NoError(t, err)
l2Opts.Value = big.NewInt(params.Ether)
// Ensure L1 has enough funds for the withdrawal by depositing an equal amount into the OptimismPortal
l1Opts, err := bind.NewKeyedTransactorWithChainID(testSuite.OpCfg.Secrets.Alice, testSuite.OpCfg.L1ChainIDBig())
require.NoError(t, err)
l1Opts.Value = l2Opts.Value
depositTx, err := optimismPortal.Receive(l1Opts)
require.NoError(t, err)
_, err = utils.WaitReceiptOK(testCtx, testSuite.L1Client, depositTx.Hash())
require.NoError(t, err)
// (1) Test Withdrawal Initiation
withdrawTx, err := l2StandardBridge.Withdraw(l2Opts, predeploys.LegacyERC20ETHAddr, l2Opts.Value, 200_000, []byte{byte(1)})
require.NoError(t, err)
withdrawReceipt, err := utils.WaitReceiptOK(testCtx, testSuite.L2Client, withdrawTx.Hash())
require.NoError(t, err)
// wait for processor catchup
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l2Header := testSuite.Indexer.L2Processor.LatestProcessedHeader()
return l2Header != nil && l2Header.Number.Uint64() >= withdrawReceipt.BlockNumber.Uint64(), nil
}))
aliceWithdrawals, err := testSuite.DB.BridgeTransfers.L2BridgeWithdrawalsByAddress(aliceAddr)
require.NoError(t, err)
require.Len(t, aliceWithdrawals, 1)
require.Equal(t, withdrawTx.Hash(), aliceWithdrawals[0].L2TransactionHash)
msgPassed, err := withdrawals.ParseMessagePassed(withdrawReceipt)
require.NoError(t, err)
withdrawalHash, err := withdrawals.WithdrawalHash(msgPassed)
require.NoError(t, err)
withdrawal := aliceWithdrawals[0].L2BridgeWithdrawal
require.Equal(t, withdrawalHash, withdrawal.WithdrawalHash)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.L1TokenAddress)
require.Equal(t, predeploys.LegacyERC20ETHAddr, withdrawal.TokenPair.L2TokenAddress)
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.Equal(t, byte(1), withdrawal.Tx.Data[0])
// (2) Test Withdrawal Proven/Finalized. Test the sql join queries to populate the right transaction
require.Nil(t, withdrawal.ProvenL1EventGUID)
require.Nil(t, withdrawal.FinalizedL1EventGUID)
require.Empty(t, aliceWithdrawals[0].ProvenL1TransactionHash)
require.Empty(t, aliceWithdrawals[0].FinalizedL1TransactionHash)
// wait for processor catchup
proveReceipt, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
require.NoError(t, utils.WaitFor(testCtx, 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.L1Processor.LatestProcessedHeader()
return l1Header != nil && l1Header.Number.Uint64() >= finalizeReceipt.BlockNumber.Uint64(), nil
}))
aliceWithdrawals, err = testSuite.DB.BridgeTransfers.L2BridgeWithdrawalsByAddress(aliceAddr)
require.NoError(t, err)
require.NotNil(t, aliceWithdrawals[0].L2BridgeWithdrawal.ProvenL1EventGUID)
require.NotNil(t, aliceWithdrawals[0].L2BridgeWithdrawal.FinalizedL1EventGUID)
require.Equal(t, proveReceipt.TxHash, aliceWithdrawals[0].ProvenL1TransactionHash)
require.Equal(t, finalizeReceipt.TxHash, aliceWithdrawals[0].FinalizedL1TransactionHash)
}
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
op_e2e "github.com/ethereum-optimism/optimism/op-e2e" op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
_ "github.com/jackc/pgx/v5/stdlib" _ "github.com/jackc/pgx/v5/stdlib"
...@@ -33,6 +34,10 @@ type E2ETestSuite struct { ...@@ -33,6 +34,10 @@ type E2ETestSuite struct {
// Rollup // Rollup
OpCfg *op_e2e.SystemConfig OpCfg *op_e2e.SystemConfig
OpSys *op_e2e.System OpSys *op_e2e.System
// Clients
L1Client *ethclient.Client
L2Client *ethclient.Client
} }
func createE2ETestSuite(t *testing.T) E2ETestSuite { func createE2ETestSuite(t *testing.T) E2ETestSuite {
...@@ -48,16 +53,9 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite { ...@@ -48,16 +53,9 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
opSys, err := opCfg.Start() opSys, err := opCfg.Start()
require.NoError(t, err) require.NoError(t, err)
l1Contracts := processor.L1Contracts{
OptimismPortal: opCfg.L1Deployments.OptimismPortalProxy,
L2OutputOracle: opCfg.L1Deployments.L2OutputOracleProxy,
L1CrossDomainMessenger: opCfg.L1Deployments.L1CrossDomainMessengerProxy,
L1StandardBridge: opCfg.L1Deployments.L1StandardBridgeProxy,
L1ERC721Bridge: opCfg.L1Deployments.L1ERC721BridgeProxy,
}
// Indexer Configuration and Start // Indexer Configuration and Start
indexerCfg := config.Config{ indexerCfg := config.Config{
Logger: logger,
DB: config.DBConfig{ DB: config.DBConfig{
Host: "127.0.0.1", Host: "127.0.0.1",
Port: 5432, Port: 5432,
...@@ -68,9 +66,14 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite { ...@@ -68,9 +66,14 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
L1RPC: opSys.Nodes["l1"].HTTPEndpoint(), L1RPC: opSys.Nodes["l1"].HTTPEndpoint(),
L2RPC: opSys.Nodes["sequencer"].HTTPEndpoint(), L2RPC: opSys.Nodes["sequencer"].HTTPEndpoint(),
}, },
Logger: logger,
Chain: config.ChainConfig{ Chain: config.ChainConfig{
L1Contracts: l1Contracts, L1Contracts: processor.L1Contracts{
OptimismPortal: opCfg.L1Deployments.OptimismPortalProxy,
L2OutputOracle: opCfg.L1Deployments.L2OutputOracleProxy,
L1CrossDomainMessenger: opCfg.L1Deployments.L1CrossDomainMessengerProxy,
L1StandardBridge: opCfg.L1Deployments.L1StandardBridgeProxy,
L1ERC721Bridge: opCfg.L1Deployments.L1ERC721BridgeProxy,
},
}, },
} }
...@@ -99,11 +102,13 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite { ...@@ -99,11 +102,13 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
}) })
return E2ETestSuite{ return E2ETestSuite{
t: t, t: t,
DB: db, DB: db,
Indexer: indexer, Indexer: indexer,
OpCfg: &opCfg, OpCfg: &opCfg,
OpSys: opSys, OpSys: opSys,
L1Client: opSys.Clients["l1"],
L2Client: opSys.Clients["sequencer"],
} }
} }
......
package utils
import (
"errors"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type DepositInfo struct {
*bindings.OptimismPortalTransactionDeposited
DepositTx *types.DepositTx
}
func ParseDepositInfo(depositReceipt *types.Receipt) (*DepositInfo, error) {
optimismPortal, err := bindings.NewOptimismPortal(common.Address{}, nil)
if err != nil {
return nil, err
}
for _, log := range depositReceipt.Logs {
if log.Topics[0] == derive.DepositEventABIHash {
portalTxDeposited, err := optimismPortal.ParseTransactionDeposited(*log)
if err != nil {
return nil, err
}
depositTx, err := derive.UnmarshalDepositLogEvent(log)
if err != nil {
return nil, err
}
return &DepositInfo{portalTxDeposited, depositTx}, nil
}
}
return nil, errors.New("cannot find deposit event in receipt")
}
...@@ -67,12 +67,12 @@ CREATE TABLE IF NOT EXISTS output_proposals ( ...@@ -67,12 +67,12 @@ CREATE TABLE IF NOT EXISTS output_proposals (
* BRIDGING DATA * BRIDGING DATA
*/ */
CREATE TABLE IF NOT EXISTS deposits ( CREATE TABLE IF NOT EXISTS l1_bridge_deposits (
guid VARCHAR PRIMARY KEY NOT NULL, guid VARCHAR PRIMARY KEY NOT NULL,
-- Event causing the deposit -- Event causing the deposit
initiated_l1_event_guid VARCHAR NOT NULL REFERENCES l1_contract_events(guid), initiated_l1_event_guid VARCHAR NOT NULL REFERENCES l1_contract_events(guid),
sent_message_nonce UINT256 UNIQUE, cross_domain_messenger_nonce UINT256 UNIQUE,
-- Finalization marker for the deposit -- Finalization marker for the deposit
finalized_l2_event_guid VARCHAR REFERENCES l2_contract_events(guid), finalized_l2_event_guid VARCHAR REFERENCES l2_contract_events(guid),
...@@ -88,12 +88,12 @@ CREATE TABLE IF NOT EXISTS deposits ( ...@@ -88,12 +88,12 @@ CREATE TABLE IF NOT EXISTS deposits (
timestamp INTEGER NOT NULL CHECK (timestamp > 0) timestamp INTEGER NOT NULL CHECK (timestamp > 0)
); );
CREATE TABLE IF NOT EXISTS withdrawals ( CREATE TABLE IF NOT EXISTS l2_bridge_withdrawals (
guid VARCHAR PRIMARY KEY NOT NULL, guid VARCHAR PRIMARY KEY NOT NULL,
-- Event causing this withdrawal -- Event causing this withdrawal
initiated_l2_event_guid VARCHAR NOT NULL REFERENCES l2_contract_events(guid), initiated_l2_event_guid VARCHAR NOT NULL REFERENCES l2_contract_events(guid),
sent_message_nonce UINT256 UNIQUE, cross_domain_messenger_nonce UINT256 UNIQUE,
-- Multistep (bedrock) process of a withdrawal -- Multistep (bedrock) process of a withdrawal
withdrawal_hash VARCHAR NOT NULL, withdrawal_hash VARCHAR NOT NULL,
......
...@@ -255,13 +255,13 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -255,13 +255,13 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
return err return err
} }
deposits := make([]*database.Deposit, len(initiatedDepositEvents)) deposits := make([]*database.L1BridgeDeposit, len(initiatedDepositEvents))
for i, initiatedBridgeEvent := range initiatedDepositEvents { for i, initiatedBridgeEvent := range initiatedDepositEvents {
deposits[i] = &database.Deposit{ deposits[i] = &database.L1BridgeDeposit{
GUID: uuid.New(), GUID: uuid.New(),
InitiatedL1EventGUID: initiatedBridgeEvent.RawEvent.GUID, InitiatedL1EventGUID: initiatedBridgeEvent.RawEvent.GUID,
SentMessageNonce: database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce}, CrossDomainMessengerNonce: database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce},
TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken}, TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{ Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From, FromAddress: initiatedBridgeEvent.From,
ToAddress: initiatedBridgeEvent.To, ToAddress: initiatedBridgeEvent.To,
...@@ -274,7 +274,7 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -274,7 +274,7 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
if len(deposits) > 0 { if len(deposits) > 0 {
processLog.Info("detected L1StandardBridge deposits", "num", len(deposits)) processLog.Info("detected L1StandardBridge deposits", "num", len(deposits))
err := db.Bridge.StoreDeposits(deposits) err := db.BridgeTransfers.StoreL1BridgeDeposits(deposits)
if err != nil { if err != nil {
return err return err
} }
...@@ -286,47 +286,39 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -286,47 +286,39 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
return err return err
} }
// we manually keep track since not every proven withdrawal is a standard bridge withdrawal latestL2Header, err := db.Blocks.LatestL2BlockHeader()
if err != nil {
return err
} else if len(provenWithdrawalEvents) > 0 && latestL2Header == nil {
return errors.New("no indexed L2 state to process any proven L1 transactions")
}
numProvenWithdrawals := 0 numProvenWithdrawals := 0
for _, provenWithdrawalEvent := range provenWithdrawalEvents { for _, provenWithdrawalEvent := range provenWithdrawalEvents {
withdrawalHash := provenWithdrawalEvent.WithdrawalHash withdrawalHash := provenWithdrawalEvent.WithdrawalHash
withdrawal, err := db.Bridge.WithdrawalByHash(withdrawalHash) withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalByWithdrawalHash(withdrawalHash)
if err != nil { if err != nil {
return err return err
} } else if withdrawal == nil {
// NOTE: This needs to be updated to identify if this CrossDomainMessenger message is a StandardBridge message. This
// Check if the L2Processor is behind or really has missed an event. We can compare against the // will be easier to do once we index cross domain messages and track its lifecyle separately
// OptimismPortal#ProvenWithdrawal on-chain mapping relative to the latest indexed L2 height
if withdrawal == nil {
// This needs to be updated to read from config as well as correctly identify if the CrossDomainMessenger message is a standard
// bridge message. This will easier to do once we index passed messages separately which will include the right To/From fields
if provenWithdrawalEvent.From != common.HexToAddress("0x4200000000000000000000000000000000000007") || provenWithdrawalEvent.To != l1Contracts.L1CrossDomainMessenger { if provenWithdrawalEvent.From != common.HexToAddress("0x4200000000000000000000000000000000000007") || provenWithdrawalEvent.To != l1Contracts.L1CrossDomainMessenger {
// non-bridge withdrawal // non-bridge withdrawal
continue continue
} }
// Query for the the proven withdrawal on-chain // Check if the L2Processor is behind or really has missed an event. Since L2 timestamps
provenWithdrawal, err := OptimismPortalQueryProvenWithdrawal(rawEthClient, l1Contracts.OptimismPortal, withdrawalHash) // are derived from L1, we can simply compare timestamps
if err != nil { if provenWithdrawalEvent.RawEvent.Timestamp > latestL2Header.Timestamp {
return err processLog.Warn("behind on indexed L2StandardBridge withdrawals")
}
latestL2Header, err := db.Blocks.LatestL2BlockHeader()
if err != nil {
return err
}
if latestL2Header == nil || provenWithdrawal.L2OutputIndex.Cmp(latestL2Header.Number.Int) > 0 {
processLog.Warn("behind on indexed L2 withdrawals")
return errors.New("waiting for L2Processor to catch up") return errors.New("waiting for L2Processor to catch up")
} else { } else {
processLog.Crit("missing indexed withdrawal for this proven event") processLog.Crit("missing indexed L2StandardBridge withdrawal for this proven event")
return errors.New("missing withdrawal message") return errors.New("missing withdrawal message")
} }
} }
err = db.Bridge.MarkProvenWithdrawalEvent(withdrawal.GUID, provenWithdrawalEvent.RawEvent.GUID) err = db.BridgeTransfers.MarkProvenL2BridgeWithdrawalEvent(withdrawal.GUID, provenWithdrawalEvent.RawEvent.GUID)
if err != nil { if err != nil {
return err return err
} }
...@@ -346,7 +338,7 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -346,7 +338,7 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
for _, finalizedBridgeEvent := range finalizedWithdrawalEvents { for _, finalizedBridgeEvent := range finalizedWithdrawalEvents {
nonce := finalizedBridgeEvent.CrossDomainMessengerNonce nonce := finalizedBridgeEvent.CrossDomainMessengerNonce
withdrawal, err := db.Bridge.WithdrawalByMessageNonce(nonce) withdrawal, err := db.BridgeTransfers.L2BridgeWithdrawalByCrossDomainMessengerNonce(nonce)
if err != nil { if err != nil {
processLog.Error("error querying associated withdrawal messsage using nonce", "cross_domain_messenger_nonce", nonce) processLog.Error("error querying associated withdrawal messsage using nonce", "cross_domain_messenger_nonce", nonce)
return err return err
...@@ -359,7 +351,7 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -359,7 +351,7 @@ func l1BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
return errors.New("missing withdrawal message") return errors.New("missing withdrawal message")
} }
err = db.Bridge.MarkFinalizedWithdrawalEvent(withdrawal.GUID, finalizedBridgeEvent.RawEvent.GUID) err = db.BridgeTransfers.MarkFinalizedL2BridgeWithdrawalEvent(withdrawal.GUID, finalizedBridgeEvent.RawEvent.GUID)
if err != nil { if err != nil {
processLog.Error("error finalizing withdrawal", "err", err) processLog.Error("error finalizing withdrawal", "err", err)
return err return err
......
...@@ -183,7 +183,7 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -183,7 +183,7 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
return err return err
} }
withdrawals := make([]*database.Withdrawal, len(initiatedWithdrawalEvents)) withdrawals := make([]*database.L2BridgeWithdrawal, len(initiatedWithdrawalEvents))
for i, initiatedBridgeEvent := range initiatedWithdrawalEvents { for i, initiatedBridgeEvent := range initiatedWithdrawalEvents {
log := events.eventLog[initiatedBridgeEvent.RawEvent.GUID] log := events.eventLog[initiatedBridgeEvent.RawEvent.GUID]
...@@ -195,12 +195,12 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -195,12 +195,12 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
return err return err
} }
withdrawals[i] = &database.Withdrawal{ withdrawals[i] = &database.L2BridgeWithdrawal{
GUID: uuid.New(), GUID: uuid.New(),
InitiatedL2EventGUID: initiatedBridgeEvent.RawEvent.GUID, InitiatedL2EventGUID: initiatedBridgeEvent.RawEvent.GUID,
SentMessageNonce: database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce}, CrossDomainMessengerNonce: database.U256{Int: initiatedBridgeEvent.CrossDomainMessengerNonce},
WithdrawalHash: msgPassedData.WithdrawalHash, WithdrawalHash: msgPassedData.WithdrawalHash,
TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken}, TokenPair: database.TokenPair{L1TokenAddress: initiatedBridgeEvent.LocalToken, L2TokenAddress: initiatedBridgeEvent.RemoteToken},
Tx: database.Transaction{ Tx: database.Transaction{
FromAddress: initiatedBridgeEvent.From, FromAddress: initiatedBridgeEvent.From,
ToAddress: initiatedBridgeEvent.To, ToAddress: initiatedBridgeEvent.To,
...@@ -213,7 +213,7 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -213,7 +213,7 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
if len(withdrawals) > 0 { if len(withdrawals) > 0 {
processLog.Info("detected L2StandardBridge withdrawals", "num", len(withdrawals)) processLog.Info("detected L2StandardBridge withdrawals", "num", len(withdrawals))
err := db.Bridge.StoreWithdrawals(withdrawals) err := db.BridgeTransfers.StoreL2BridgeWithdrawals(withdrawals)
if err != nil { if err != nil {
return err return err
} }
...@@ -225,30 +225,33 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl ...@@ -225,30 +225,33 @@ func l2BridgeProcessContractEvents(processLog log.Logger, db *database.DB, ethCl
return err return err
} }
latestL1Header, err := db.Blocks.LatestL1BlockHeader()
if err != nil {
return err
} else if len(finalizationBridgeEvents) > 0 && latestL1Header == nil {
return errors.New("no indexed L1 state to process any L2 bridge finalizations")
}
for _, finalizedBridgeEvent := range finalizationBridgeEvents { for _, finalizedBridgeEvent := range finalizationBridgeEvents {
nonce := finalizedBridgeEvent.CrossDomainMessengerNonce nonce := finalizedBridgeEvent.CrossDomainMessengerNonce
deposit, err := db.Bridge.DepositByMessageNonce(nonce) deposit, err := db.BridgeTransfers.L1BridgeDepositByCrossDomainMessengerNonce(nonce)
if err != nil { if err != nil {
processLog.Error("error querying associated deposit messsage using nonce", "cross_domain_messenger_nonce", nonce) processLog.Error("error querying associated deposit messsage using nonce", "cross_domain_messenger_nonce", nonce)
return err return err
} else if deposit == nil { } else if deposit == nil {
latestNonce, err := db.Bridge.LatestDepositMessageNonce() // Check if the L1Processor is behind or really has missed an event. Since L2 timestamps
if err != nil { // are derived from L1, we can simply compare timestamps
return err if finalizedBridgeEvent.RawEvent.Timestamp > latestL1Header.Timestamp {
} processLog.Warn("behind on indexed L1StandardBridge deposits")
// Check if the L1Processor is behind or really has missed an event
if latestNonce == nil || nonce.Cmp(latestNonce) > 0 {
processLog.Warn("behind on indexed L1 deposits")
return errors.New("waiting for L1Processor to catch up") return errors.New("waiting for L1Processor to catch up")
} else { } else {
processLog.Crit("missing indexed deposit for this finalization event") processLog.Crit("missing indexed L1StandardBridge deposit for this finalization event")
return errors.New("missing deposit message") return errors.New("missing deposit message")
} }
} }
err = db.Bridge.MarkFinalizedDepositEvent(deposit.GUID, finalizedBridgeEvent.RawEvent.GUID) err = db.BridgeTransfers.MarkFinalizedL1BridgeDepositEvent(deposit.GUID, finalizedBridgeEvent.RawEvent.GUID)
if err != nil { if err != nil {
processLog.Error("error finalizing deposit", "err", err) processLog.Error("error finalizing deposit", "err", err)
return err return err
......
This diff is collapsed.
...@@ -13,17 +13,16 @@ import ( ...@@ -13,17 +13,16 @@ import (
) )
var ( var (
l1EthRpc = "http://example.com:8545" l1EthRpc = "http://example.com:8545"
gameAddressValue = "0xaa00000000000000000000000000000000000000" gameAddressValue = "0xaa00000000000000000000000000000000000000"
preimageOracleAddressValue = "0xbb00000000000000000000000000000000000000" cannonBin = "./bin/cannon"
cannonBin = "./bin/cannon" cannonServer = "./bin/op-program"
cannonServer = "./bin/op-program" cannonPreState = "./pre.json"
cannonPreState = "./pre.json" cannonDatadir = "./test_data"
cannonDatadir = "./test_data" cannonL2 = "http://example.com:9545"
cannonL2 = "http://example.com:9545" alphabetTrace = "abcdefghijz"
alphabetTrace = "abcdefghijz" agreeWithProposedOutput = "true"
agreeWithProposedOutput = "true" gameDepth = "4"
gameDepth = "4"
) )
func TestLogLevel(t *testing.T) { func TestLogLevel(t *testing.T) {
...@@ -43,14 +42,14 @@ func TestLogLevel(t *testing.T) { ...@@ -43,14 +42,14 @@ func TestLogLevel(t *testing.T) {
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet)) cfg := configForArgs(t, addRequiredArgs(config.TraceTypeAlphabet))
defaultCfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), common.HexToAddress(preimageOracleAddressValue), config.TraceTypeAlphabet, true, 4) defaultCfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), config.TraceTypeAlphabet, true, 4)
// Add in the extra CLI options required when using alphabet trace type // Add in the extra CLI options required when using alphabet trace type
defaultCfg.AlphabetTrace = alphabetTrace defaultCfg.AlphabetTrace = alphabetTrace
require.Equal(t, defaultCfg, cfg) require.Equal(t, defaultCfg, cfg)
} }
func TestDefaultConfigIsValid(t *testing.T) { func TestDefaultConfigIsValid(t *testing.T) {
cfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), common.HexToAddress(preimageOracleAddressValue), config.TraceTypeAlphabet, true, 4) cfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), config.TraceTypeAlphabet, true, 4)
// Add in options that are required based on the specific trace type // Add in options that are required based on the specific trace type
// To avoid needing to specify unused options, these aren't included in the params for NewConfig // To avoid needing to specify unused options, these aren't included in the params for NewConfig
cfg.AlphabetTrace = alphabetTrace cfg.AlphabetTrace = alphabetTrace
...@@ -140,26 +139,6 @@ func TestGameDepth(t *testing.T) { ...@@ -140,26 +139,6 @@ func TestGameDepth(t *testing.T) {
}) })
} }
func TestPreimageOracleAddress(t *testing.T) {
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--preimage-oracle-address"))
})
t.Run("Required", func(t *testing.T) {
verifyArgsInvalid(t, "flag preimage-oracle-address is required", addRequiredArgsExcept(config.TraceTypeCannon, "--preimage-oracle-address"))
})
t.Run("Valid", func(t *testing.T) {
addr := common.Address{0xbb, 0xcc, 0xdd}
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeCannon, "--preimage-oracle-address", "--preimage-oracle-address="+addr.Hex()))
require.Equal(t, addr, cfg.PreimageOracleAddress)
})
t.Run("Invalid", func(t *testing.T) {
verifyArgsInvalid(t, "invalid address: foo", addRequiredArgsExcept(config.TraceTypeCannon, "--preimage-oracle-address", "--preimage-oracle-address=foo"))
})
}
func TestCannonBin(t *testing.T) { func TestCannonBin(t *testing.T) {
t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) { t.Run("NotRequiredForAlphabetTrace", func(t *testing.T) {
configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--cannon-bin")) configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--cannon-bin"))
...@@ -288,7 +267,6 @@ func requiredArgs(traceType config.TraceType) map[string]string { ...@@ -288,7 +267,6 @@ func requiredArgs(traceType config.TraceType) map[string]string {
"--agree-with-proposed-output": agreeWithProposedOutput, "--agree-with-proposed-output": agreeWithProposedOutput,
"--l1-eth-rpc": l1EthRpc, "--l1-eth-rpc": l1EthRpc,
"--game-address": gameAddressValue, "--game-address": gameAddressValue,
"--preimage-oracle-address": preimageOracleAddressValue,
"--trace-type": traceType.String(), "--trace-type": traceType.String(),
} }
switch traceType { switch traceType {
......
...@@ -61,7 +61,6 @@ const DefaultCannonSnapshotFreq = uint(10_000) ...@@ -61,7 +61,6 @@ const DefaultCannonSnapshotFreq = uint(10_000)
type Config struct { type Config struct {
L1EthRpc string // L1 RPC Url L1EthRpc string // L1 RPC Url
GameAddress common.Address // Address of the fault game GameAddress common.Address // Address of the fault game
PreimageOracleAddress common.Address // Address of the pre-image oracle
AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output
GameDepth int // Depth of the game tree GameDepth int // Depth of the game tree
...@@ -84,15 +83,13 @@ type Config struct { ...@@ -84,15 +83,13 @@ type Config struct {
func NewConfig( func NewConfig(
l1EthRpc string, l1EthRpc string,
gameAddress common.Address, gameAddress common.Address,
preimageOracleAddress common.Address,
traceType TraceType, traceType TraceType,
agreeWithProposedOutput bool, agreeWithProposedOutput bool,
gameDepth int, gameDepth int,
) Config { ) Config {
return Config{ return Config{
L1EthRpc: l1EthRpc, L1EthRpc: l1EthRpc,
GameAddress: gameAddress, GameAddress: gameAddress,
PreimageOracleAddress: preimageOracleAddress,
AgreeWithProposedOutput: agreeWithProposedOutput, AgreeWithProposedOutput: agreeWithProposedOutput,
GameDepth: gameDepth, GameDepth: gameDepth,
...@@ -116,9 +113,6 @@ func (c Config) Check() error { ...@@ -116,9 +113,6 @@ func (c Config) Check() error {
return ErrMissingTraceType return ErrMissingTraceType
} }
if c.TraceType == TraceTypeCannon { if c.TraceType == TraceTypeCannon {
if c.PreimageOracleAddress == (common.Address{}) {
return ErrMissingPreimageOracleAddress
}
if c.CannonBin == "" { if c.CannonBin == "" {
return ErrMissingCannonBin return ErrMissingCannonBin
} }
......
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
var ( var (
validL1EthRpc = "http://localhost:8545" validL1EthRpc = "http://localhost:8545"
validGameAddress = common.HexToAddress("0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139") validGameAddress = common.HexToAddress("0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139")
validPreimageOracleAddress = common.HexToAddress("0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139")
validAlphabetTrace = "abcdefgh" validAlphabetTrace = "abcdefgh"
validCannonBin = "./bin/cannon" validCannonBin = "./bin/cannon"
validCannonOpProgramBin = "./bin/op-program" validCannonOpProgramBin = "./bin/op-program"
...@@ -23,7 +22,7 @@ var ( ...@@ -23,7 +22,7 @@ var (
) )
func validConfig(traceType TraceType) Config { func validConfig(traceType TraceType) Config {
cfg := NewConfig(validL1EthRpc, validGameAddress, validPreimageOracleAddress, traceType, agreeWithProposedOutput, gameDepth) cfg := NewConfig(validL1EthRpc, validGameAddress, traceType, agreeWithProposedOutput, gameDepth)
switch traceType { switch traceType {
case TraceTypeAlphabet: case TraceTypeAlphabet:
cfg.AlphabetTrace = validAlphabetTrace cfg.AlphabetTrace = validAlphabetTrace
...@@ -74,12 +73,6 @@ func TestAlphabetTraceRequired(t *testing.T) { ...@@ -74,12 +73,6 @@ func TestAlphabetTraceRequired(t *testing.T) {
require.ErrorIs(t, config.Check(), ErrMissingAlphabetTrace) require.ErrorIs(t, config.Check(), ErrMissingAlphabetTrace)
} }
func TestCannonPreimageOracleAddressRequired(t *testing.T) {
config := validConfig(TraceTypeCannon)
config.PreimageOracleAddress = common.Address{}
require.ErrorIs(t, config.Check(), ErrMissingPreimageOracleAddress)
}
func TestCannonBinRequired(t *testing.T) { func TestCannonBinRequired(t *testing.T) {
config := validConfig(TraceTypeCannon) config := validConfig(TraceTypeCannon)
config.CannonBin = "" config.CannonBin = ""
......
...@@ -56,31 +56,44 @@ func NewExecutor(logger log.Logger, cfg *config.Config, inputs localGameInputs) ...@@ -56,31 +56,44 @@ func NewExecutor(logger log.Logger, cfg *config.Config, inputs localGameInputs)
} }
func (e *Executor) GenerateProof(ctx context.Context, dir string, i uint64) error { func (e *Executor) GenerateProof(ctx context.Context, dir string, i uint64) error {
start, err := e.selectSnapshot(e.logger, filepath.Join(e.dataDir, snapsDir), e.absolutePreState, i) snapshotDir := filepath.Join(dir, snapsDir)
start, err := e.selectSnapshot(e.logger, snapshotDir, e.absolutePreState, i)
if err != nil { if err != nil {
return fmt.Errorf("find starting snapshot: %w", err) return fmt.Errorf("find starting snapshot: %w", err)
} }
proofDir := filepath.Join(dir, proofsDir)
dataDir := filepath.Join(e.dataDir, preimagesDir)
args := []string{ args := []string{
"run", "run",
"--input", start, "--input", start,
"--output", filepath.Join(dir, "out.json"),
"--meta", "",
"--proof-at", "=" + strconv.FormatUint(i, 10), "--proof-at", "=" + strconv.FormatUint(i, 10),
"--stop-at", "=" + strconv.FormatUint(i+1, 10), "--stop-at", "=" + strconv.FormatUint(i+1, 10),
"--proof-fmt", filepath.Join(dir, proofsDir, "%d.json"), "--proof-fmt", filepath.Join(proofDir, "%d.json"),
"--snapshot-at", "%" + strconv.FormatUint(uint64(e.snapshotFreq), 10), "--snapshot-at", "%" + strconv.FormatUint(uint64(e.snapshotFreq), 10),
"--snapshot-fmt", filepath.Join(e.dataDir, snapsDir, "%d.json"), "--snapshot-fmt", filepath.Join(snapshotDir, "%d.json"),
"--", "--",
e.server, e.server,
"--l1", e.l1, "--l1", e.l1,
"--l2", e.l2, "--l2", e.l2,
"--datadir", filepath.Join(e.dataDir, preimagesDir), "--datadir", dataDir,
"--l1.head", e.inputs.l1Head.Hex(), "--l1.head", e.inputs.l1Head.Hex(),
"--l2.head", e.inputs.l2Head.Hex(), "--l2.head", e.inputs.l2Head.Hex(),
"--l2.outputroot", e.inputs.l2OutputRoot.Hex(), "--l2.outputroot", e.inputs.l2OutputRoot.Hex(),
"--l2.claim", e.inputs.l2Claim.Hex(), "--l2.claim", e.inputs.l2Claim.Hex(),
"--l2.blocknumber", e.inputs.l2BlockNumber.Text(10), "--l2.blocknumber", e.inputs.l2BlockNumber.Text(10),
"--l2.chainid", e.inputs.l2ChainId.Text(10),
} }
if err := os.MkdirAll(snapshotDir, 0755); err != nil {
return fmt.Errorf("could not create snapshot directory %v: %w", snapshotDir, err)
}
if err := os.MkdirAll(dataDir, 0755); err != nil {
return fmt.Errorf("could not create preimage cache directory %v: %w", dataDir, err)
}
if err := os.MkdirAll(proofDir, 0755); err != nil {
return fmt.Errorf("could not create proofs directory %v: %w", proofDir, err)
}
e.logger.Info("Generating trace", "proof", i, "cmd", e.cannon, "args", args) e.logger.Info("Generating trace", "proof", i, "cmd", e.cannon, "args", args)
return e.cmdExecutor(ctx, e.logger.New("proof", i), e.cannon, args...) return e.cmdExecutor(ctx, e.logger.New("proof", i), e.cannon, args...)
} }
......
...@@ -20,7 +20,7 @@ const execTestCannonPrestate = "/foo/pre.json" ...@@ -20,7 +20,7 @@ const execTestCannonPrestate = "/foo/pre.json"
func TestGenerateProof(t *testing.T) { func TestGenerateProof(t *testing.T) {
input := "starting.json" input := "starting.json"
cfg := config.NewConfig("http://localhost:8888", common.Address{0xaa}, common.Address{0xbb}, config.TraceTypeCannon, true, 5) cfg := config.NewConfig("http://localhost:8888", common.Address{0xaa}, config.TraceTypeCannon, true, 5)
cfg.CannonDatadir = t.TempDir() cfg.CannonDatadir = t.TempDir()
cfg.CannonAbsolutePreState = "pre.json" cfg.CannonAbsolutePreState = "pre.json"
cfg.CannonBin = "./bin/cannon" cfg.CannonBin = "./bin/cannon"
...@@ -30,7 +30,6 @@ func TestGenerateProof(t *testing.T) { ...@@ -30,7 +30,6 @@ func TestGenerateProof(t *testing.T) {
inputs := localGameInputs{ inputs := localGameInputs{
l1Head: common.Hash{0x11}, l1Head: common.Hash{0x11},
l2ChainId: big.NewInt(2342),
l2Head: common.Hash{0x22}, l2Head: common.Hash{0x22},
l2OutputRoot: common.Hash{0x33}, l2OutputRoot: common.Hash{0x33},
l2Claim: common.Hash{0x44}, l2Claim: common.Hash{0x44},
...@@ -54,9 +53,15 @@ func TestGenerateProof(t *testing.T) { ...@@ -54,9 +53,15 @@ func TestGenerateProof(t *testing.T) {
} }
err := executor.GenerateProof(context.Background(), cfg.CannonDatadir, 150_000_000) err := executor.GenerateProof(context.Background(), cfg.CannonDatadir, 150_000_000)
require.NoError(t, err) require.NoError(t, err)
require.DirExists(t, filepath.Join(cfg.CannonDatadir, preimagesDir))
require.DirExists(t, filepath.Join(cfg.CannonDatadir, proofsDir))
require.DirExists(t, filepath.Join(cfg.CannonDatadir, snapsDir))
require.Equal(t, cfg.CannonBin, binary) require.Equal(t, cfg.CannonBin, binary)
require.Equal(t, "run", subcommand) require.Equal(t, "run", subcommand)
require.Equal(t, input, args["--input"]) require.Equal(t, input, args["--input"])
require.Contains(t, args, "--meta")
require.Equal(t, "", args["--meta"])
require.Equal(t, filepath.Join(cfg.CannonDatadir, "out.json"), args["--output"])
require.Equal(t, "=150000000", args["--proof-at"]) require.Equal(t, "=150000000", args["--proof-at"])
require.Equal(t, "=150000001", args["--stop-at"]) require.Equal(t, "=150000001", args["--stop-at"])
require.Equal(t, "%500", args["--snapshot-at"]) require.Equal(t, "%500", args["--snapshot-at"])
...@@ -73,7 +78,6 @@ func TestGenerateProof(t *testing.T) { ...@@ -73,7 +78,6 @@ func TestGenerateProof(t *testing.T) {
require.Equal(t, inputs.l2OutputRoot.Hex(), args["--l2.outputroot"]) require.Equal(t, inputs.l2OutputRoot.Hex(), args["--l2.outputroot"])
require.Equal(t, inputs.l2Claim.Hex(), args["--l2.claim"]) require.Equal(t, inputs.l2Claim.Hex(), args["--l2.claim"])
require.Equal(t, "3333", args["--l2.blocknumber"]) require.Equal(t, "3333", args["--l2.blocknumber"])
require.Equal(t, "2342", args["--l2.chainid"])
} }
func TestRunCmdLogsOutput(t *testing.T) { func TestRunCmdLogsOutput(t *testing.T) {
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
type localGameInputs struct { type localGameInputs struct {
l1Head common.Hash l1Head common.Hash
l2ChainId *big.Int
l2Head common.Hash l2Head common.Hash
l2OutputRoot common.Hash l2OutputRoot common.Hash
l2Claim common.Hash l2Claim common.Hash
...@@ -39,10 +38,6 @@ func fetchLocalInputs(ctx context.Context, gameAddr common.Address, caller GameI ...@@ -39,10 +38,6 @@ func fetchLocalInputs(ctx context.Context, gameAddr common.Address, caller GameI
if err != nil { if err != nil {
return localGameInputs{}, fmt.Errorf("fetch L1 head for game %v: %w", gameAddr, err) return localGameInputs{}, fmt.Errorf("fetch L1 head for game %v: %w", gameAddr, err)
} }
l2ChainId, err := l2Client.ChainID(ctx)
if err != nil {
return localGameInputs{}, fmt.Errorf("fetch L2 chain ID: %w", err)
}
proposals, err := caller.Proposals(opts) proposals, err := caller.Proposals(opts)
if err != nil { if err != nil {
...@@ -58,7 +53,6 @@ func fetchLocalInputs(ctx context.Context, gameAddr common.Address, caller GameI ...@@ -58,7 +53,6 @@ func fetchLocalInputs(ctx context.Context, gameAddr common.Address, caller GameI
return localGameInputs{ return localGameInputs{
l1Head: l1Head, l1Head: l1Head,
l2ChainId: l2ChainId,
l2Head: l2Head, l2Head: l2Head,
l2OutputRoot: agreedOutput.OutputRoot, l2OutputRoot: agreedOutput.OutputRoot,
l2Claim: claimedOutput.OutputRoot, l2Claim: claimedOutput.OutputRoot,
......
...@@ -40,7 +40,6 @@ func TestFetchLocalInputs(t *testing.T) { ...@@ -40,7 +40,6 @@ func TestFetchLocalInputs(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, l1Client.l1Head, inputs.l1Head) require.Equal(t, l1Client.l1Head, inputs.l1Head)
require.Equal(t, l2Client.chainID, inputs.l2ChainId)
require.Equal(t, l2Client.header.Hash(), inputs.l2Head) require.Equal(t, l2Client.header.Hash(), inputs.l2Head)
require.EqualValues(t, l1Client.starting.OutputRoot, inputs.l2OutputRoot) require.EqualValues(t, l1Client.starting.OutputRoot, inputs.l2OutputRoot)
require.EqualValues(t, l1Client.disputed.OutputRoot, inputs.l2Claim) require.EqualValues(t, l1Client.disputed.OutputRoot, inputs.l2Claim)
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"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"
...@@ -28,8 +29,36 @@ type cannonUpdater struct { ...@@ -28,8 +29,36 @@ type cannonUpdater struct {
preimageOracleAddr common.Address preimageOracleAddr common.Address
} }
// NewOracleUpdater returns a new updater. // NewOracleUpdater returns a new updater. The pre-image oracle address is loaded from the fault dispute game.
func NewOracleUpdater( func NewOracleUpdater(
ctx context.Context,
logger log.Logger,
txMgr txmgr.TxManager,
fdgAddr common.Address,
client bind.ContractCaller,
) (*cannonUpdater, error) {
gameCaller, err := bindings.NewFaultDisputeGameCaller(fdgAddr, client)
if err != nil {
return nil, fmt.Errorf("create caller for game %v: %w", fdgAddr, err)
}
opts := &bind.CallOpts{Context: ctx}
vm, err := gameCaller.VM(opts)
if err != nil {
return nil, fmt.Errorf("failed to load VM address from game %v: %w", fdgAddr, err)
}
mipsCaller, err := bindings.NewMIPSCaller(vm, client)
if err != nil {
return nil, fmt.Errorf("failed to create MIPS caller for address %v: %w", vm, err)
}
oracleAddr, err := mipsCaller.Oracle(opts)
if err != nil {
return nil, fmt.Errorf("failed to load pre-image oracle address from game %v: %w", fdgAddr, err)
}
return NewOracleUpdaterWithOracle(logger, txMgr, fdgAddr, oracleAddr)
}
// NewOracleUpdaterWithOracle returns a new updater using a specified pre-image oracle address.
func NewOracleUpdaterWithOracle(
logger log.Logger, logger log.Logger,
txMgr txmgr.TxManager, txMgr txmgr.TxManager,
fdgAddr common.Address, fdgAddr common.Address,
......
...@@ -64,7 +64,7 @@ func newTestCannonUpdater(t *testing.T, sendFails bool) (*cannonUpdater, *mockTx ...@@ -64,7 +64,7 @@ func newTestCannonUpdater(t *testing.T, sendFails bool) (*cannonUpdater, *mockTx
from: mockFdgAddress, from: mockFdgAddress,
sendFails: sendFails, sendFails: sendFails,
} }
updater, err := NewOracleUpdater(logger, txMgr, mockFdgAddress, mockPreimageOracleAddress) updater, err := NewOracleUpdaterWithOracle(logger, txMgr, mockFdgAddress, mockPreimageOracleAddress)
require.NoError(t, err) require.NoError(t, err)
return updater, txMgr return updater, txMgr
} }
......
...@@ -49,7 +49,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se ...@@ -49,7 +49,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se
if err != nil { if err != nil {
return nil, fmt.Errorf("create cannon trace provider: %w", err) return nil, fmt.Errorf("create cannon trace provider: %w", err)
} }
updater, err = cannon.NewOracleUpdater(logger, txMgr, cfg.GameAddress, cfg.PreimageOracleAddress) updater, err = cannon.NewOracleUpdater(ctx, logger, txMgr, cfg.GameAddress, client)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create the cannon updater: %w", err) return nil, fmt.Errorf("failed to create the cannon updater: %w", err)
} }
......
...@@ -10,7 +10,6 @@ import ( ...@@ -10,7 +10,6 @@ import (
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
...@@ -59,11 +58,6 @@ var ( ...@@ -59,11 +58,6 @@ var (
Usage: "Correct Alphabet Trace (alphabet trace type only)", Usage: "Correct Alphabet Trace (alphabet trace type only)",
EnvVars: prefixEnvVars("ALPHABET"), EnvVars: prefixEnvVars("ALPHABET"),
} }
PreimageOracleAddressFlag = &cli.StringFlag{
Name: "preimage-oracle-address",
Usage: "Address of the Preimage Oracle contract (only required for cannon).",
EnvVars: prefixEnvVars("PREIMAGE_ORACLE_ADDRESS"),
}
CannonBinFlag = &cli.StringFlag{ CannonBinFlag = &cli.StringFlag{
Name: "cannon-bin", Name: "cannon-bin",
Usage: "Path to cannon executable to use when generating trace data (cannon trace type only)", Usage: "Path to cannon executable to use when generating trace data (cannon trace type only)",
...@@ -109,7 +103,6 @@ var requiredFlags = []cli.Flag{ ...@@ -109,7 +103,6 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags // optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{ var optionalFlags = []cli.Flag{
AlphabetFlag, AlphabetFlag,
PreimageOracleAddressFlag,
CannonBinFlag, CannonBinFlag,
CannonServerFlag, CannonServerFlag,
CannonPreStateFlag, CannonPreStateFlag,
...@@ -137,9 +130,6 @@ func CheckRequired(ctx *cli.Context) error { ...@@ -137,9 +130,6 @@ func CheckRequired(ctx *cli.Context) error {
gameType := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name))) gameType := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name)))
switch gameType { switch gameType {
case config.TraceTypeCannon: case config.TraceTypeCannon:
if !ctx.IsSet(PreimageOracleAddressFlag.Name) {
return fmt.Errorf("flag %s is required", PreimageOracleAddressFlag.Name)
}
if !ctx.IsSet(CannonBinFlag.Name) { if !ctx.IsSet(CannonBinFlag.Name) {
return fmt.Errorf("flag %s is required", CannonBinFlag.Name) return fmt.Errorf("flag %s is required", CannonBinFlag.Name)
} }
...@@ -179,21 +169,11 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) { ...@@ -179,21 +169,11 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
traceTypeFlag := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name))) traceTypeFlag := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name)))
preimageOracleAddress := common.Address{}
preimageOracleValue := ctx.String(PreimageOracleAddressFlag.Name)
if traceTypeFlag == config.TraceTypeCannon || preimageOracleValue != "" {
preimageOracleAddress, err = opservice.ParseAddress(preimageOracleValue)
if err != nil {
return nil, err
}
}
return &config.Config{ return &config.Config{
// Required Flags // Required Flags
L1EthRpc: ctx.String(L1EthRpcFlag.Name), L1EthRpc: ctx.String(L1EthRpcFlag.Name),
TraceType: traceTypeFlag, TraceType: traceTypeFlag,
GameAddress: dgfAddress, GameAddress: dgfAddress,
PreimageOracleAddress: preimageOracleAddress,
AlphabetTrace: ctx.String(AlphabetFlag.Name), AlphabetTrace: ctx.String(AlphabetFlag.Name),
CannonBin: ctx.String(CannonBinFlag.Name), CannonBin: ctx.String(CannonBinFlag.Name),
CannonServer: ctx.String(CannonServerFlag.Name), CannonServer: ctx.String(CannonServerFlag.Name),
......
# @eth-optimism/fee-estimation # @eth-optimism/fee-estimation
## 0.15.2
### Patch Changes
- [#6609](https://github.com/ethereum-optimism/optimism/pull/6609) [`0e83c4452`](https://github.com/ethereum-optimism/optimism/commit/0e83c44522e1a13e4d5c1395fd4dc9dbae8be08d) Thanks [@roninjin10](https://github.com/roninjin10)! - Fixed bug with 'estimateFees' not taking into account the l2 gas price
## 0.15.1 ## 0.15.1
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/fee-estimation", "name": "@eth-optimism/fee-estimation",
"version": "0.15.1", "version": "0.15.2",
"description": "Lightweight library for doing OP-Chain gas estimation", "description": "Lightweight library for doing OP-Chain gas estimation",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
......
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