Commit 601e0e5e authored by Hamdi Allam's avatar Hamdi Allam

e2e test indexing l1 blocks with contract events

parent 808bc8bd
package database package database
import ( import (
"errors"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -46,6 +48,11 @@ type L2ContractEvent struct { ...@@ -46,6 +48,11 @@ type L2ContractEvent struct {
} }
type ContractEventsView interface { type ContractEventsView interface {
L1ContractEvent(uuid.UUID) (*L1ContractEvent, error)
L1ContractEventByTxLogIndex(common.Hash, uint64) (*L1ContractEvent, error)
L2ContractEvent(uuid.UUID) (*L2ContractEvent, error)
L2ContractEventByTxLogIndex(common.Hash, uint64) (*L2ContractEvent, error)
} }
type ContractEventsDB interface { type ContractEventsDB interface {
...@@ -74,9 +81,65 @@ func (db *contractEventsDB) StoreL1ContractEvents(events []*L1ContractEvent) err ...@@ -74,9 +81,65 @@ func (db *contractEventsDB) StoreL1ContractEvents(events []*L1ContractEvent) err
return result.Error return result.Error
} }
func (db *contractEventsDB) L1ContractEvent(uuid uuid.UUID) (*L1ContractEvent, error) {
var l1ContractEvent L1ContractEvent
result := db.gorm.Where(&ContractEvent{GUID: uuid}).Take(&l1ContractEvent)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &l1ContractEvent, nil
}
func (db *contractEventsDB) L1ContractEventByTxLogIndex(txHash common.Hash, logIndex uint64) (*L1ContractEvent, error) {
var l1ContractEvent L1ContractEvent
result := db.gorm.Where(&ContractEvent{TransactionHash: txHash, LogIndex: logIndex}).Take(&l1ContractEvent)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &l1ContractEvent, nil
}
// L2 // L2
func (db *contractEventsDB) StoreL2ContractEvents(events []*L2ContractEvent) error { func (db *contractEventsDB) StoreL2ContractEvents(events []*L2ContractEvent) error {
result := db.gorm.Create(&events) result := db.gorm.Create(&events)
return result.Error return result.Error
} }
func (db *contractEventsDB) L2ContractEvent(uuid uuid.UUID) (*L2ContractEvent, error) {
var l2ContractEvent L2ContractEvent
result := db.gorm.Where(&ContractEvent{GUID: uuid}).Take(&l2ContractEvent)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &l2ContractEvent, nil
}
func (db *contractEventsDB) L2ContractEventByTxLogIndex(txHash common.Hash, logIndex uint64) (*L2ContractEvent, error) {
var l2ContractEvent L2ContractEvent
result := db.gorm.Where(&ContractEvent{TransactionHash: txHash, LogIndex: logIndex}).Take(&l2ContractEvent)
if result.Error != nil {
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, result.Error
}
return &l2ContractEvent, nil
}
package integration_tests package e2e_tests
import ( import (
"context" "context"
...@@ -7,17 +7,20 @@ import ( ...@@ -7,17 +7,20 @@ import (
"time" "time"
"github.com/ethereum-optimism/optimism/indexer/node" "github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processor"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-bindings/predeploys"
e2eutils "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" e2eutils "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestE2E(t *testing.T) { func TestE2EBlockHeaders(t *testing.T) {
testSuite := createE2ETestSuite(t) testSuite := createE2ETestSuite(t)
l1Client := testSuite.OpSys.Clients["l1"] l1Client := testSuite.OpSys.Clients["l1"]
...@@ -44,7 +47,7 @@ func TestE2E(t *testing.T) { ...@@ -44,7 +47,7 @@ func TestE2E(t *testing.T) {
return (l1Header != nil && l1Header.Number.Uint64() >= l1Height) && (l2Header != nil && l2Header.Number.Uint64() >= 9), nil return (l1Header != nil && l1Header.Number.Uint64() >= l1Height) && (l2Header != nil && l2Header.Number.Uint64() >= 9), nil
})) }))
t.Run("indexes L2 headers", func(t *testing.T) { t.Run("indexes L2 blocks", func(t *testing.T) {
latestL2Header, err := testSuite.DB.Blocks.LatestL2BlockHeader() latestL2Header, err := testSuite.DB.Blocks.LatestL2BlockHeader()
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, latestL2Header) require.NotNil(t, latestL2Header)
...@@ -104,6 +107,35 @@ func TestE2E(t *testing.T) { ...@@ -104,6 +107,35 @@ func TestE2E(t *testing.T) {
} }
}) })
t.Run("indexes L1 blocks of interest", func(t *testing.T) { t.Run("indexes L1 logs and associated blocks", func(t *testing.T) {
testCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
devContracts := processor.DevL1Contracts().ToSlice()
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)
for _, log := range logs {
contractEvent, err := testSuite.DB.ContractEvents.L1ContractEventByTxLogIndex(log.TxHash, uint64(log.Index))
require.NoError(t, err)
require.Equal(t, log.Topics[0], contractEvent.EventSignature)
require.Equal(t, log.BlockHash, contractEvent.BlockHash)
require.Equal(t, log.TxHash, contractEvent.TransactionHash)
require.Equal(t, log.Index, uint(contractEvent.LogIndex))
// ensure the block is also indexed
block, err := l1Client.BlockByNumber(testCtx, big.NewInt(int64(log.BlockNumber)))
require.NoError(t, err)
require.Equal(t, block.Time(), contractEvent.Timestamp)
l1BlockHeader, err := testSuite.DB.Blocks.L1BlockHeader(block.Number())
require.NoError(t, err)
require.Equal(t, block.Hash(), l1BlockHeader.Hash)
require.Equal(t, block.ParentHash(), l1BlockHeader.ParentHash)
require.Equal(t, block.Number(), l1BlockHeader.Number.Int)
require.Equal(t, block.Time(), l1BlockHeader.Timestamp)
}
}) })
} }
package integration_tests package e2e_tests
import ( import (
"context" "context"
...@@ -13,6 +13,7 @@ import ( ...@@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer" "github.com/ethereum-optimism/optimism/indexer"
"github.com/ethereum-optimism/optimism/indexer/config" "github.com/ethereum-optimism/optimism/indexer/config"
"github.com/ethereum-optimism/optimism/indexer/database" "github.com/ethereum-optimism/optimism/indexer/database"
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/log" "github.com/ethereum/go-ethereum/log"
......
...@@ -9,8 +9,6 @@ import ( ...@@ -9,8 +9,6 @@ import (
"github.com/ethereum-optimism/optimism/indexer/database" "github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/node" "github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processor" "github.com/ethereum-optimism/optimism/indexer/processor"
"github.com/ethereum/go-ethereum/common"
) )
// Indexer contains the necessary resources for // Indexer contains the necessary resources for
...@@ -31,13 +29,7 @@ func NewIndexer(cfg config.Config) (*Indexer, error) { ...@@ -31,13 +29,7 @@ func NewIndexer(cfg config.Config) (*Indexer, error) {
} }
// L1 Processor (hardhat devnet contracts). Make this configurable // L1 Processor (hardhat devnet contracts). Make this configurable
l1Contracts := processor.L1Contracts{ l1Contracts := processor.DevL1Contracts()
OptimismPortal: common.HexToAddress("0x6900000000000000000000000000000000000000"),
L2OutputOracle: common.HexToAddress("0x6900000000000000000000000000000000000001"),
L1CrossDomainMessenger: common.HexToAddress("0x6900000000000000000000000000000000000002"),
L1StandardBridge: common.HexToAddress("0x6900000000000000000000000000000000000003"),
L1ERC721Bridge: common.HexToAddress("0x6900000000000000000000000000000000000004"),
}
l1EthClient, err := node.DialEthClient(cfg.RPCs.L1RPC) l1EthClient, err := node.DialEthClient(cfg.RPCs.L1RPC)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -47,8 +39,8 @@ func NewIndexer(cfg config.Config) (*Indexer, error) { ...@@ -47,8 +39,8 @@ func NewIndexer(cfg config.Config) (*Indexer, error) {
return nil, err return nil, err
} }
// L2Processor // L2Processor (predeploys). Although most likely the right setting, make this configurable?
l2Contracts := processor.L2ContractPredeploys() // Make this configurable l2Contracts := processor.L2ContractPredeploys()
l2EthClient, err := node.DialEthClient(cfg.RPCs.L2RPC) l2EthClient, err := node.DialEthClient(cfg.RPCs.L2RPC)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -34,12 +34,17 @@ type L1Contracts struct { ...@@ -34,12 +34,17 @@ type L1Contracts struct {
// Remove afterwards? // Remove afterwards?
} }
type checkpointAbi struct { func DevL1Contracts() L1Contracts {
l2OutputOracle *abi.ABI return L1Contracts{
legacyStateCommitmentChain *abi.ABI OptimismPortal: common.HexToAddress("0x6900000000000000000000000000000000000000"),
L2OutputOracle: common.HexToAddress("0x6900000000000000000000000000000000000001"),
L1CrossDomainMessenger: common.HexToAddress("0x6900000000000000000000000000000000000002"),
L1StandardBridge: common.HexToAddress("0x6900000000000000000000000000000000000003"),
L1ERC721Bridge: common.HexToAddress("0x6900000000000000000000000000000000000004"),
}
} }
func (c L1Contracts) toSlice() []common.Address { func (c L1Contracts) ToSlice() []common.Address {
fields := reflect.VisibleFields(reflect.TypeOf(c)) fields := reflect.VisibleFields(reflect.TypeOf(c))
v := reflect.ValueOf(c) v := reflect.ValueOf(c)
...@@ -51,6 +56,11 @@ func (c L1Contracts) toSlice() []common.Address { ...@@ -51,6 +56,11 @@ func (c L1Contracts) toSlice() []common.Address {
return contracts return contracts
} }
type checkpointAbi struct {
l2OutputOracle *abi.ABI
legacyStateCommitmentChain *abi.ABI
}
type L1Processor struct { type L1Processor struct {
processor processor
} }
...@@ -107,7 +117,7 @@ func NewL1Processor(logger log.Logger, ethClient node.EthClient, db *database.DB ...@@ -107,7 +117,7 @@ func NewL1Processor(logger log.Logger, ethClient node.EthClient, db *database.DB
func l1ProcessFn(processLog log.Logger, ethClient node.EthClient, l1Contracts L1Contracts, checkpointAbi checkpointAbi) ProcessFn { func l1ProcessFn(processLog log.Logger, ethClient node.EthClient, l1Contracts L1Contracts, checkpointAbi checkpointAbi) ProcessFn {
rawEthClient := ethclient.NewClient(ethClient.RawRpcClient()) rawEthClient := ethclient.NewClient(ethClient.RawRpcClient())
contractAddrs := l1Contracts.toSlice() contractAddrs := l1Contracts.ToSlice()
processLog.Info("processor configured with contracts", "contracts", l1Contracts) processLog.Info("processor configured with contracts", "contracts", l1Contracts)
outputProposedEventName := "OutputProposed" outputProposedEventName := "OutputProposed"
......
...@@ -39,7 +39,7 @@ func L2ContractPredeploys() L2Contracts { ...@@ -39,7 +39,7 @@ func L2ContractPredeploys() L2Contracts {
} }
} }
func (c L2Contracts) toSlice() []common.Address { func (c L2Contracts) ToSlice() []common.Address {
fields := reflect.VisibleFields(reflect.TypeOf(c)) fields := reflect.VisibleFields(reflect.TypeOf(c))
v := reflect.ValueOf(c) v := reflect.ValueOf(c)
...@@ -94,7 +94,7 @@ func NewL2Processor(logger log.Logger, ethClient node.EthClient, db *database.DB ...@@ -94,7 +94,7 @@ func NewL2Processor(logger log.Logger, ethClient node.EthClient, db *database.DB
func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2Contracts) ProcessFn { func l2ProcessFn(processLog log.Logger, ethClient node.EthClient, l2Contracts L2Contracts) ProcessFn {
rawEthClient := ethclient.NewClient(ethClient.RawRpcClient()) rawEthClient := ethclient.NewClient(ethClient.RawRpcClient())
contractAddrs := l2Contracts.toSlice() contractAddrs := l2Contracts.ToSlice()
processLog.Info("processor configured with contracts", "contracts", l2Contracts) processLog.Info("processor configured with contracts", "contracts", l2Contracts)
return func(db *database.DB, headers []*types.Header) error { return func(db *database.DB, headers []*types.Header) error {
numHeaders := len(headers) numHeaders := len(headers)
......
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