Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
19e581d8
Unverified
Commit
19e581d8
authored
Oct 09, 2022
by
Matthew Slipper
Committed by
GitHub
Oct 09, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
indexer: Upgrade everything else, add itests (#3669)
parent
5a9928c0
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
443 additions
and
158 deletions
+443
-158
lemon-files-rescue.md
.changeset/lemon-files-rescue.md
+5
-0
config.yml
.circleci/config.yml
+1
-1
config.go
indexer/config.go
+38
-55
eth.go
indexer/db/eth.go
+5
-6
flags.go
indexer/flags/flags.go
+27
-14
indexer.go
indexer/indexer.go
+61
-43
bedrock_test.go
indexer/integration_tests/bedrock_test.go
+304
-0
sentry_log.go
indexer/sentry_log.go
+0
-38
service.go
indexer/services/l2/service.go
+2
-1
No files found.
.changeset/lemon-files-rescue.md
0 → 100644
View file @
19e581d8
---
'
@eth-optimism/indexer'
:
minor
---
Bedrock support
.circleci/config.yml
View file @
19e581d8
...
...
@@ -432,7 +432,7 @@ jobs:
name
:
Test
command
:
|
mkdir -p /test-results
gotestsum --junitfile /test-results/tests.xml
DB_USER=postgres
gotestsum --junitfile /test-results/tests.xml
working_directory
:
<<parameters.working_directory>>
-
when
:
condition
:
...
...
indexer/config.go
View file @
19e581d8
...
...
@@ -4,6 +4,7 @@ import (
"errors"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli"
...
...
@@ -20,15 +21,8 @@ var (
type
Config
struct
{
/* Required Params */
// BuildEnv identifies the environment this binary is intended for, i.e.
// production, development, etc.
BuildEnv
string
// EthNetworkName identifies the intended Ethereum network.
EthNetworkName
string
// ChainID identifies the chain being indexed.
ChainID
int64
ChainID
u
int64
// L1EthRpc is the HTTP provider URL for L1.
L1EthRpc
string
...
...
@@ -36,8 +30,8 @@ type Config struct {
// L2EthRpc is the HTTP provider URL for L1.
L2EthRpc
string
// L
2GenesisBlockHash is the l2 genesis block hash
.
L
2GenesisBlockHash
string
// L
1AddressManagerAddress is the address of the address manager for L1
.
L
1AddressManagerAddress
string
// PollInterval is the delay between querying L2 for more transaction
// and creating a new batch.
...
...
@@ -68,22 +62,8 @@ type Config struct {
// are printed using JSON.
LogTerminal
bool
// SentryEnable if true, logs any error messages to sentry. SentryDsn
// must also be set if SentryEnable is true.
SentryEnable
bool
// SentryDsn is the sentry Data Source Name.
SentryDsn
string
// SentryTraceRate the frequency with which Sentry should flush buffered
// events.
SentryTraceRate
time
.
Duration
// StartBlockNumber is the block number to start indexing from.
StartBlockNumber
uint64
// StartBlockHash is the block hash to start indexing from.
StartBlockHash
string
// L1StartBlockNumber is the block number to start indexing L1 from.
L1StartBlockNumber
uint64
// ConfDepth is the number of confirmations after which headers are
// considered confirmed.
...
...
@@ -111,6 +91,13 @@ type Config struct {
// DisableIndexer enables/disables the indexer.
DisableIndexer
bool
// Bedrock enabled Bedrock indexing.
Bedrock
bool
BedrockL1StandardBridgeAddress
common
.
Address
BedrockOptimismPortalAddress
common
.
Address
}
// NewConfig parses the Config from the provided flags or environment variables.
...
...
@@ -118,33 +105,30 @@ type Config struct {
func
NewConfig
(
ctx
*
cli
.
Context
)
(
Config
,
error
)
{
cfg
:=
Config
{
/* Required Flags */
BuildEnv
:
ctx
.
GlobalString
(
flags
.
BuildEnvFlag
.
Name
),
EthNetworkName
:
ctx
.
GlobalString
(
flags
.
EthNetworkNameFlag
.
Name
),
ChainID
:
ctx
.
GlobalInt64
(
flags
.
ChainIDFlag
.
Name
),
L1EthRpc
:
ctx
.
GlobalString
(
flags
.
L1EthRPCFlag
.
Name
),
L2EthRpc
:
ctx
.
GlobalString
(
flags
.
L2EthRPCFlag
.
Name
),
L2GenesisBlockHash
:
ctx
.
GlobalString
(
flags
.
L2GenesisBlockHashFlag
.
Name
),
DBHost
:
ctx
.
GlobalString
(
flags
.
DBHostFlag
.
Name
),
DBPort
:
ctx
.
GlobalUint64
(
flags
.
DBPortFlag
.
Name
),
DBUser
:
ctx
.
GlobalString
(
flags
.
DBUserFlag
.
Name
),
DBPassword
:
ctx
.
GlobalString
(
flags
.
DBPasswordFlag
.
Name
),
DBName
:
ctx
.
GlobalString
(
flags
.
DBNameFlag
.
Name
),
ChainID
:
ctx
.
GlobalUint64
(
flags
.
ChainIDFlag
.
Name
),
L1EthRpc
:
ctx
.
GlobalString
(
flags
.
L1EthRPCFlag
.
Name
),
L2EthRpc
:
ctx
.
GlobalString
(
flags
.
L2EthRPCFlag
.
Name
),
L1AddressManagerAddress
:
ctx
.
GlobalString
(
flags
.
L1AddressManagerAddressFlag
.
Name
),
DBHost
:
ctx
.
GlobalString
(
flags
.
DBHostFlag
.
Name
),
DBPort
:
ctx
.
GlobalUint64
(
flags
.
DBPortFlag
.
Name
),
DBUser
:
ctx
.
GlobalString
(
flags
.
DBUserFlag
.
Name
),
DBPassword
:
ctx
.
GlobalString
(
flags
.
DBPasswordFlag
.
Name
),
DBName
:
ctx
.
GlobalString
(
flags
.
DBNameFlag
.
Name
),
/* Optional Flags */
DisableIndexer
:
ctx
.
GlobalBool
(
flags
.
DisableIndexer
.
Name
),
LogLevel
:
ctx
.
GlobalString
(
flags
.
LogLevelFlag
.
Name
),
LogTerminal
:
ctx
.
GlobalBool
(
flags
.
LogTerminalFlag
.
Name
),
SentryEnable
:
ctx
.
GlobalBool
(
flags
.
SentryEnableFlag
.
Name
),
SentryDsn
:
ctx
.
GlobalString
(
flags
.
SentryDsnFlag
.
Name
),
SentryTraceRate
:
ctx
.
GlobalDuration
(
flags
.
SentryTraceRateFlag
.
Name
),
StartBlockNumber
:
ctx
.
GlobalUint64
(
flags
.
StartBlockNumberFlag
.
Name
),
StartBlockHash
:
ctx
.
GlobalString
(
flags
.
StartBlockHashFlag
.
Name
),
ConfDepth
:
ctx
.
GlobalUint64
(
flags
.
ConfDepthFlag
.
Name
),
MaxHeaderBatchSize
:
ctx
.
GlobalUint64
(
flags
.
MaxHeaderBatchSizeFlag
.
Name
),
MetricsServerEnable
:
ctx
.
GlobalBool
(
flags
.
MetricsServerEnableFlag
.
Name
),
RESTHostname
:
ctx
.
GlobalString
(
flags
.
RESTHostnameFlag
.
Name
),
RESTPort
:
ctx
.
GlobalUint64
(
flags
.
RESTPortFlag
.
Name
),
MetricsHostname
:
ctx
.
GlobalString
(
flags
.
MetricsHostnameFlag
.
Name
),
MetricsPort
:
ctx
.
GlobalUint64
(
flags
.
MetricsPortFlag
.
Name
),
Bedrock
:
ctx
.
GlobalBool
(
flags
.
BedrockFlag
.
Name
),
BedrockL1StandardBridgeAddress
:
common
.
HexToAddress
(
ctx
.
GlobalString
(
flags
.
BedrockL1StandardBridgeAddress
.
Name
)),
BedrockOptimismPortalAddress
:
common
.
HexToAddress
(
ctx
.
GlobalString
(
flags
.
BedrockOptimismPortalAddress
.
Name
)),
DisableIndexer
:
ctx
.
GlobalBool
(
flags
.
DisableIndexer
.
Name
),
LogLevel
:
ctx
.
GlobalString
(
flags
.
LogLevelFlag
.
Name
),
LogTerminal
:
ctx
.
GlobalBool
(
flags
.
LogTerminalFlag
.
Name
),
L1StartBlockNumber
:
ctx
.
GlobalUint64
(
flags
.
L1StartBlockNumberFlag
.
Name
),
ConfDepth
:
ctx
.
GlobalUint64
(
flags
.
ConfDepthFlag
.
Name
),
MaxHeaderBatchSize
:
ctx
.
GlobalUint64
(
flags
.
MaxHeaderBatchSizeFlag
.
Name
),
MetricsServerEnable
:
ctx
.
GlobalBool
(
flags
.
MetricsServerEnableFlag
.
Name
),
RESTHostname
:
ctx
.
GlobalString
(
flags
.
RESTHostnameFlag
.
Name
),
RESTPort
:
ctx
.
GlobalUint64
(
flags
.
RESTPortFlag
.
Name
),
MetricsHostname
:
ctx
.
GlobalString
(
flags
.
MetricsHostnameFlag
.
Name
),
MetricsPort
:
ctx
.
GlobalUint64
(
flags
.
MetricsPortFlag
.
Name
),
}
err
:=
ValidateConfig
(
&
cfg
)
...
...
@@ -168,9 +152,8 @@ func ValidateConfig(cfg *Config) error {
return
err
}
// Ensure the Sentry Data Source Name is set when using Sentry.
if
cfg
.
SentryEnable
&&
cfg
.
SentryDsn
==
""
{
return
ErrSentryDSNNotSet
if
cfg
.
Bedrock
&&
(
cfg
.
BedrockL1StandardBridgeAddress
==
common
.
Address
{}
||
cfg
.
BedrockOptimismPortalAddress
==
common
.
Address
{})
{
return
errors
.
New
(
"must specify l1 standard bridge and optimism portal addresses in bedrock mode"
)
}
return
nil
...
...
indexer/db/eth.go
View file @
19e581d8
package
db
import
"github.com/ethereum/go-ethereum/common"
import
(
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
)
var
ETHL1Address
common
.
Address
...
...
@@ -13,14 +16,10 @@ var ETHL1Token = &Token{
Decimals
:
18
,
}
// ETHL2Address is a placeholder address for differentiating ETH transactions
// from ERC20 transactions on L2.
var
ETHL2Address
=
common
.
HexToAddress
(
"0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000"
)
// ETHL2Token is a placeholder token for differentiating ETH transactions from
// ERC20 transactions on L2.
var
ETHL2Token
=
&
Token
{
Address
:
ETHL2Address
.
String
()
,
Address
:
predeploys
.
LegacyERC20ETH
,
Name
:
"Ethereum"
,
Symbol
:
"ETH"
,
Decimals
:
18
,
...
...
indexer/flags/flags.go
View file @
19e581d8
...
...
@@ -46,11 +46,11 @@ var (
Required
:
true
,
EnvVar
:
prefixEnvVar
(
"L2_ETH_RPC"
),
}
L
2GenesisBlockHash
Flag
=
cli
.
StringFlag
{
Name
:
"l
2-genesis-block-hash
"
,
Usage
:
"
Genesis block hash of the L2 chain
"
,
L
1AddressManagerAddress
Flag
=
cli
.
StringFlag
{
Name
:
"l
1-address-manager-address
"
,
Usage
:
"
Address of the L1 address manager
"
,
Required
:
true
,
EnvVar
:
prefixEnvVar
(
"L
2_GENESIS_BLOCK_HASH
"
),
EnvVar
:
prefixEnvVar
(
"L
1_ADDRESS_MANAGER_ADDRESS
"
),
}
DBHostFlag
=
cli
.
StringFlag
{
Name
:
"db-host"
,
...
...
@@ -83,6 +83,23 @@ var (
EnvVar
:
prefixEnvVar
(
"DB_NAME"
),
}
/* Bedrock Flags */
BedrockFlag
=
cli
.
BoolFlag
{
Name
:
"bedrock"
,
Usage
:
"Whether or not this indexer should operate in Bedrock mode"
,
EnvVar
:
prefixEnvVar
(
"BEDROCK"
),
}
BedrockL1StandardBridgeAddress
=
cli
.
BoolFlag
{
Name
:
"bedrock.l1-standard-bridge-address"
,
Usage
:
"Address of the L1 standard bridge"
,
EnvVar
:
prefixEnvVar
(
"BEDROCK_L1_STANDARD_BRIDGE"
),
}
BedrockOptimismPortalAddress
=
cli
.
BoolFlag
{
Name
:
"bedrock.portal-address"
,
Usage
:
"Address of the portal"
,
EnvVar
:
prefixEnvVar
(
"BEDROCK_OPTIMISM_PORTAL"
),
}
/* Optional Flags */
DisableIndexer
=
cli
.
BoolFlag
{
...
...
@@ -120,18 +137,12 @@ var (
Value
:
50
*
time
.
Millisecond
,
EnvVar
:
prefixEnvVar
(
"SENTRY_TRACE_RATE"
),
}
StartBlockNumberFlag
=
cli
.
Uint64Flag
{
L1
StartBlockNumberFlag
=
cli
.
Uint64Flag
{
Name
:
"start-block-number"
,
Usage
:
"The block number to start indexing from. Must be use together with start block hash"
,
Value
:
0
,
EnvVar
:
prefixEnvVar
(
"START_BLOCK_NUMBER"
),
}
StartBlockHashFlag
=
cli
.
StringFlag
{
Name
:
"start-block-hash"
,
Usage
:
"The block hash to start indexing from. Must be use together with start block number"
,
Value
:
"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"
,
EnvVar
:
prefixEnvVar
(
"START_BLOCK_HASH"
),
}
ConfDepthFlag
=
cli
.
Uint64Flag
{
Name
:
"conf-depth"
,
Usage
:
"The number of confirmations after which headers are considered confirmed"
,
...
...
@@ -181,7 +192,7 @@ var requiredFlags = []cli.Flag{
ChainIDFlag
,
L1EthRPCFlag
,
L2EthRPCFlag
,
L
2GenesisBlockHash
Flag
,
L
1AddressManagerAddress
Flag
,
DBHostFlag
,
DBPortFlag
,
DBUserFlag
,
...
...
@@ -190,6 +201,9 @@ var requiredFlags = []cli.Flag{
}
var
optionalFlags
=
[]
cli
.
Flag
{
BedrockFlag
,
BedrockL1StandardBridgeAddress
,
BedrockOptimismPortalAddress
,
DisableIndexer
,
LogLevelFlag
,
LogTerminalFlag
,
...
...
@@ -198,8 +212,7 @@ var optionalFlags = []cli.Flag{
SentryTraceRateFlag
,
ConfDepthFlag
,
MaxHeaderBatchSizeFlag
,
StartBlockNumberFlag
,
StartBlockHashFlag
,
L1StartBlockNumberFlag
,
RESTHostnameFlag
,
RESTPortFlag
,
MetricsServerEnableFlag
,
...
...
indexer/indexer.go
View file @
19e581d8
...
...
@@ -11,6 +11,7 @@ import (
"time"
"github.com/ethereum-optimism/optimism/indexer/services"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum-optimism/optimism/indexer/server"
...
...
@@ -22,7 +23,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/getsentry/sentry-go"
"github.com/gorilla/mux"
"github.com/urfave/cli"
)
...
...
@@ -44,15 +44,9 @@ func Main(gitVersion string) func(ctx *cli.Context) error {
return
err
}
// The call to defer is done here so that any errors logged from
// this point on are posted to Sentry before exiting.
if
cfg
.
SentryEnable
{
defer
sentry
.
Flush
(
2
*
time
.
Second
)
}
log
.
Info
(
"Initializing indexer"
)
indexer
,
err
:=
NewIndexer
(
cfg
,
gitVersion
)
indexer
,
err
:=
NewIndexer
(
cfg
)
if
err
!=
nil
{
log
.
Error
(
"Unable to create indexer"
,
"error"
,
err
)
return
err
...
...
@@ -87,32 +81,18 @@ type Indexer struct {
router
*
mux
.
Router
metrics
*
metrics
.
Metrics
db
*
database
.
Database
server
*
http
.
Server
}
// NewIndexer initializes the Indexer, gathering any resources
// that will be needed by the TxIndexer and StateIndexer
// sub-services.
func
NewIndexer
(
cfg
Config
,
gitVersion
string
)
(
*
Indexer
,
error
)
{
func
NewIndexer
(
cfg
Config
)
(
*
Indexer
,
error
)
{
ctx
:=
context
.
Background
()
// Set up our logging. If Sentry is enabled, we will use our custom
// log handler that logs to stdout and forwards any error messages to
// Sentry for collection. Otherwise, logs will only be posted to stdout.
var
logHandler
log
.
Handler
if
cfg
.
SentryEnable
{
err
:=
sentry
.
Init
(
sentry
.
ClientOptions
{
Dsn
:
cfg
.
SentryDsn
,
Environment
:
cfg
.
EthNetworkName
,
Release
:
"indexer@"
+
gitVersion
,
TracesSampleRate
:
traceRateToFloat64
(
cfg
.
SentryTraceRate
),
Debug
:
false
,
})
if
err
!=
nil
{
return
nil
,
err
}
logHandler
=
SentryStreamHandler
(
os
.
Stdout
,
log
.
JSONFormat
())
}
else
if
cfg
.
LogTerminal
{
if
cfg
.
LogTerminal
{
logHandler
=
log
.
StreamHandler
(
os
.
Stdout
,
log
.
TerminalFormat
(
true
))
}
else
{
logHandler
=
log
.
StreamHandler
(
os
.
Stdout
,
log
.
JSONFormat
())
...
...
@@ -149,8 +129,11 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
log
.
Info
(
"metrics server enabled"
,
"host"
,
cfg
.
MetricsHostname
,
"port"
,
cfg
.
MetricsPort
)
}
dsn
:=
fmt
.
Sprintf
(
"host=%s port=%d user=%s dbname=%s sslmode=disable"
,
cfg
.
DBHost
,
cfg
.
DBPort
,
cfg
.
DBUser
,
cfg
.
DBName
)
dsn
:=
fmt
.
Sprintf
(
"host=%s port=%d dbname=%s sslmode=disable"
,
cfg
.
DBHost
,
cfg
.
DBPort
,
cfg
.
DBName
)
if
cfg
.
DBUser
!=
""
{
dsn
+=
fmt
.
Sprintf
(
" user=%s"
,
cfg
.
DBUser
)
}
if
cfg
.
DBPassword
!=
""
{
dsn
+=
fmt
.
Sprintf
(
" password=%s"
,
cfg
.
DBPassword
)
}
...
...
@@ -159,16 +142,32 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
return
nil
,
err
}
var
addrManager
services
.
AddressManager
if
cfg
.
Bedrock
{
addrManager
,
err
=
services
.
NewBedrockAddresses
(
l1Client
,
cfg
.
BedrockL1StandardBridgeAddress
,
cfg
.
BedrockOptimismPortalAddress
,
)
}
else
{
addrManager
,
err
=
services
.
NewLegacyAddresses
(
l1Client
,
common
.
HexToAddress
(
cfg
.
L1AddressManagerAddress
))
}
if
err
!=
nil
{
return
nil
,
err
}
l1IndexingService
,
err
:=
l1
.
NewService
(
l1
.
ServiceConfig
{
Context
:
ctx
,
Metrics
:
m
,
L1Client
:
l1Client
,
RawL1Client
:
rawl1Client
,
ChainID
:
big
.
NewInt
(
cfg
.
ChainID
),
ChainID
:
new
(
big
.
Int
)
.
SetUint64
(
cfg
.
ChainID
),
AddressManager
:
addrManager
,
DB
:
db
,
ConfDepth
:
cfg
.
ConfDepth
,
MaxHeaderBatchSize
:
cfg
.
MaxHeaderBatchSize
,
StartBlockNumber
:
cfg
.
StartBlockNumber
,
StartBlockNumber
:
cfg
.
L1StartBlockNumber
,
Bedrock
:
cfg
.
Bedrock
,
})
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -183,6 +182,7 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
ConfDepth
:
cfg
.
ConfDepth
,
MaxHeaderBatchSize
:
cfg
.
MaxHeaderBatchSize
,
StartBlockNumber
:
uint64
(
0
),
Bedrock
:
cfg
.
Bedrock
,
})
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -198,6 +198,7 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
airdropService
:
services
.
NewAirdrop
(
db
,
m
),
router
:
mux
.
NewRouter
(),
metrics
:
m
,
db
:
db
,
},
nil
}
...
...
@@ -210,6 +211,7 @@ func (b *Indexer) Serve() error {
b
.
router
.
HandleFunc
(
"/v1/l1/status"
,
b
.
l1IndexingService
.
GetIndexerStatus
)
.
Methods
(
"GET"
)
b
.
router
.
HandleFunc
(
"/v1/l2/status"
,
b
.
l2IndexingService
.
GetIndexerStatus
)
.
Methods
(
"GET"
)
b
.
router
.
HandleFunc
(
"/v1/deposits/0x{address:[a-fA-F0-9]{40}}"
,
b
.
l1IndexingService
.
GetDeposits
)
.
Methods
(
"GET"
)
b
.
router
.
HandleFunc
(
"/v1/withdrawal/0x{hash:[a-fA-F0-9]{64}}"
,
b
.
l2IndexingService
.
GetWithdrawalBatch
)
.
Methods
(
"GET"
)
b
.
router
.
HandleFunc
(
"/v1/withdrawals/0x{address:[a-fA-F0-9]{40}}"
,
b
.
l2IndexingService
.
GetWithdrawals
)
.
Methods
(
"GET"
)
b
.
router
.
HandleFunc
(
"/v1/airdrops/0x{address:[a-fA-F0-9]{40}}"
,
b
.
airdropService
.
GetAirdrop
)
b
.
router
.
HandleFunc
(
"/healthz"
,
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
...
...
@@ -225,8 +227,27 @@ func (b *Indexer) Serve() error {
port
:=
strconv
.
FormatUint
(
b
.
cfg
.
RESTPort
,
10
)
addr
:=
net
.
JoinHostPort
(
b
.
cfg
.
RESTHostname
,
port
)
log
.
Info
(
"indexer REST server listening on"
,
"addr"
,
addr
)
return
http
.
ListenAndServe
(
addr
,
middleware
(
c
.
Handler
(
b
.
router
)))
b
.
server
=
&
http
.
Server
{
Addr
:
addr
,
Handler
:
middleware
(
c
.
Handler
(
b
.
router
)),
}
errCh
:=
make
(
chan
error
,
1
)
go
func
()
{
errCh
<-
b
.
server
.
ListenAndServe
()
}()
// Capture server startup errors
<-
time
.
After
(
10
*
time
.
Millisecond
)
select
{
case
err
:=
<-
errCh
:
return
err
default
:
log
.
Info
(
"indexer REST server listening on"
,
"addr"
,
addr
)
return
nil
}
}
// Start starts the starts the indexing service on L1 and L2 chains and also
...
...
@@ -250,6 +271,14 @@ func (b *Indexer) Start() error {
// Stop stops the indexing service on L1 and L2 chains.
func
(
b
*
Indexer
)
Stop
()
{
b
.
db
.
Close
()
if
b
.
server
!=
nil
{
// background context here so it waits for
// conns to close
_
=
b
.
server
.
Shutdown
(
context
.
Background
())
}
if
!
b
.
cfg
.
DisableIndexer
{
b
.
l1IndexingService
.
Stop
()
b
.
l2IndexingService
.
Stop
()
...
...
@@ -271,14 +300,3 @@ func dialEthClientWithTimeout(ctx context.Context, url string) (
}
return
ethclient
.
NewClient
(
c
),
c
,
nil
}
// traceRateToFloat64 converts a time.Duration into a valid float64 for the
// Sentry client. The client only accepts values between 0.0 and 1.0, so this
// method clamps anything greater than 1 second to 1.0.
func
traceRateToFloat64
(
rate
time
.
Duration
)
float64
{
rate64
:=
float64
(
rate
)
/
float64
(
time
.
Second
)
if
rate64
>
1.0
{
rate64
=
1.0
}
return
rate64
}
indexer/integration_tests/bedrock_test.go
0 → 100644
View file @
19e581d8
package
integration_tests
import
(
"context"
"database/sql"
"encoding/json"
"fmt"
"math/big"
"net/http"
"os"
"testing"
"time"
"github.com/ethereum-optimism/optimism/indexer"
"github.com/ethereum-optimism/optimism/indexer/db"
"github.com/ethereum-optimism/optimism/indexer/services/l1"
"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-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"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/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
_
"github.com/lib/pq"
)
func
TestBedrockIndexer
(
t
*
testing
.
T
)
{
dbParams
:=
createTestDB
(
t
)
cfg
:=
op_e2e
.
DefaultSystemConfig
(
t
)
cfg
.
DeployConfig
.
FinalizationPeriodSeconds
=
2
sys
,
err
:=
cfg
.
Start
()
require
.
NoError
(
t
,
err
)
defer
sys
.
Close
()
l1Client
:=
sys
.
Clients
[
"l1"
]
l2Client
:=
sys
.
Clients
[
"sequencer"
]
fromAddr
:=
cfg
.
Secrets
.
Addresses
()
.
Alice
// wait a couple of blocks
require
.
NoError
(
t
,
e2eutils
.
WaitBlock
(
e2eutils
.
TimeoutCtx
(
t
,
30
*
time
.
Second
),
l2Client
,
10
))
l1SB
,
err
:=
bindings
.
NewL1StandardBridge
(
predeploys
.
DevL1StandardBridgeAddr
,
l1Client
)
require
.
NoError
(
t
,
err
)
l2SB
,
err
:=
bindings
.
NewL2StandardBridge
(
predeploys
.
L2StandardBridgeAddr
,
l2Client
)
require
.
NoError
(
t
,
err
)
portal
,
err
:=
bindings
.
NewOptimismPortal
(
predeploys
.
DevOptimismPortalAddr
,
l1Client
)
require
.
NoError
(
t
,
err
)
l1Opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
cfg
.
Secrets
.
Alice
,
cfg
.
L1ChainIDBig
())
require
.
NoError
(
t
,
err
)
l2Opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
cfg
.
Secrets
.
Alice
,
cfg
.
L2ChainIDBig
())
require
.
NoError
(
t
,
err
)
idxrCfg
:=
indexer
.
Config
{
ChainID
:
cfg
.
DeployConfig
.
L1ChainID
,
L1EthRpc
:
sys
.
Nodes
[
"l1"
]
.
HTTPEndpoint
(),
L2EthRpc
:
sys
.
Nodes
[
"sequencer"
]
.
HTTPEndpoint
(),
PollInterval
:
time
.
Second
,
DBHost
:
dbParams
.
Host
,
DBPort
:
dbParams
.
Port
,
DBUser
:
dbParams
.
User
,
DBPassword
:
dbParams
.
Password
,
DBName
:
dbParams
.
Name
,
LogLevel
:
"info"
,
LogTerminal
:
true
,
L1StartBlockNumber
:
0
,
ConfDepth
:
1
,
MaxHeaderBatchSize
:
2
,
RESTHostname
:
"127.0.0.1"
,
RESTPort
:
7980
,
DisableIndexer
:
false
,
Bedrock
:
true
,
BedrockL1StandardBridgeAddress
:
predeploys
.
DevL1StandardBridgeAddr
,
BedrockOptimismPortalAddress
:
predeploys
.
DevOptimismPortalAddr
,
}
idxr
,
err
:=
indexer
.
NewIndexer
(
idxrCfg
)
require
.
NoError
(
t
,
err
)
errCh
:=
make
(
chan
error
,
1
)
go
func
()
{
errCh
<-
idxr
.
Start
()
}()
t
.
Cleanup
(
func
()
{
idxr
.
Stop
()
require
.
NoError
(
t
,
<-
errCh
)
})
makeURL
:=
func
(
path
string
)
string
{
return
fmt
.
Sprintf
(
"http://%s:%d/%s"
,
idxrCfg
.
RESTHostname
,
idxrCfg
.
RESTPort
,
path
)
}
t
.
Run
(
"deposit ETH"
,
func
(
t
*
testing
.
T
)
{
l1Opts
.
Value
=
big
.
NewInt
(
params
.
Ether
)
depTx
,
err
:=
l1SB
.
DepositETH
(
l1Opts
,
200
_000
,
nil
)
require
.
NoError
(
t
,
err
)
depReceipt
,
err
:=
e2eutils
.
WaitReceiptOK
(
e2eutils
.
TimeoutCtx
(
t
,
10
*
time
.
Second
),
l1Client
,
depTx
.
Hash
())
require
.
NoError
(
t
,
err
)
require
.
Greaterf
(
t
,
len
(
depReceipt
.
Logs
),
0
,
"must have logs"
)
var
l2Hash
common
.
Hash
for
_
,
eLog
:=
range
depReceipt
.
Logs
{
if
len
(
eLog
.
Topics
)
==
0
||
eLog
.
Topics
[
0
]
!=
derive
.
DepositEventABIHash
{
continue
}
depLog
,
err
:=
derive
.
UnmarshalDepositLogEvent
(
eLog
)
require
.
NoError
(
t
,
err
)
tx
:=
types
.
NewTx
(
depLog
)
l2Hash
=
tx
.
Hash
()
}
require
.
NotEqual
(
t
,
common
.
Hash
{},
l2Hash
)
_
,
err
=
e2eutils
.
WaitReceiptOK
(
e2eutils
.
TimeoutCtx
(
t
,
15
*
time
.
Second
),
l2Client
,
l2Hash
)
require
.
NoError
(
t
,
err
)
// Poll for indexer deposit
var
depPage
*
db
.
PaginatedDeposits
require
.
NoError
(
t
,
e2eutils
.
WaitFor
(
e2eutils
.
TimeoutCtx
(
t
,
30
*
time
.
Second
),
100
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
res
:=
new
(
db
.
PaginatedDeposits
)
err
:=
getJSON
(
makeURL
(
fmt
.
Sprintf
(
"v1/deposits/%s"
,
fromAddr
)),
res
)
if
err
!=
nil
{
return
false
,
err
}
if
len
(
res
.
Deposits
)
==
0
{
return
false
,
nil
}
depPage
=
res
return
true
,
nil
}))
// Make sure deposit is what we expect
require
.
Equal
(
t
,
1
,
len
(
depPage
.
Deposits
))
deposit
:=
depPage
.
Deposits
[
0
]
require
.
Equal
(
t
,
big
.
NewInt
(
params
.
Ether
)
.
String
(),
deposit
.
Amount
)
require
.
Equal
(
t
,
depTx
.
Hash
()
.
String
(),
deposit
.
TxHash
)
require
.
Equal
(
t
,
depReceipt
.
BlockNumber
.
Uint64
(),
deposit
.
BlockNumber
)
require
.
Equal
(
t
,
fromAddr
.
String
(),
deposit
.
FromAddress
)
require
.
Equal
(
t
,
fromAddr
.
String
(),
deposit
.
ToAddress
)
require
.
EqualValues
(
t
,
db
.
ETHL1Token
,
deposit
.
L1Token
)
require
.
Equal
(
t
,
l1
.
ZeroAddress
.
String
(),
deposit
.
L2Token
)
require
.
NotEmpty
(
t
,
deposit
.
GUID
)
// Perform withdrawal through bridge
l2Opts
.
Value
=
big
.
NewInt
(
0.5
*
params
.
Ether
)
wdTx
,
err
:=
l2SB
.
Withdraw
(
l2Opts
,
predeploys
.
LegacyERC20ETHAddr
,
big
.
NewInt
(
0.5
*
params
.
Ether
),
0
,
nil
)
require
.
NoError
(
t
,
err
)
wdReceipt
,
err
:=
e2eutils
.
WaitReceiptOK
(
e2eutils
.
TimeoutCtx
(
t
,
30
*
time
.
Second
),
l2Client
,
wdTx
.
Hash
())
require
.
NoError
(
t
,
err
)
var
wdPage
*
db
.
PaginatedWithdrawals
require
.
NoError
(
t
,
e2eutils
.
WaitFor
(
e2eutils
.
TimeoutCtx
(
t
,
30
*
time
.
Second
),
100
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
res
:=
new
(
db
.
PaginatedWithdrawals
)
err
:=
getJSON
(
makeURL
(
fmt
.
Sprintf
(
"v1/withdrawals/%s"
,
fromAddr
)),
res
)
if
err
!=
nil
{
return
false
,
err
}
if
len
(
res
.
Withdrawals
)
==
0
{
return
false
,
nil
}
wdPage
=
res
return
true
,
nil
}))
require
.
Equal
(
t
,
1
,
len
(
wdPage
.
Withdrawals
))
withdrawal
:=
wdPage
.
Withdrawals
[
0
]
require
.
Nil
(
t
,
withdrawal
.
BedrockFinalizedTxHash
)
require
.
Equal
(
t
,
big
.
NewInt
(
0.5
*
params
.
Ether
)
.
String
(),
withdrawal
.
Amount
)
require
.
Equal
(
t
,
wdTx
.
Hash
()
.
String
(),
withdrawal
.
TxHash
)
require
.
Equal
(
t
,
wdReceipt
.
BlockNumber
.
Uint64
(),
withdrawal
.
BlockNumber
)
// use fromaddr twice here because the user is withdrawing
// to themselves
require
.
Equal
(
t
,
fromAddr
.
String
(),
withdrawal
.
FromAddress
)
require
.
Equal
(
t
,
fromAddr
.
String
(),
withdrawal
.
ToAddress
)
require
.
EqualValues
(
t
,
l1
.
ZeroAddress
.
String
(),
withdrawal
.
L1Token
)
require
.
Equal
(
t
,
db
.
ETHL2Token
,
withdrawal
.
L2Token
)
require
.
NotEmpty
(
t
,
withdrawal
.
GUID
)
finBlockNum
,
err
:=
withdrawals
.
WaitForFinalizationPeriod
(
e2eutils
.
TimeoutCtx
(
t
,
time
.
Minute
),
l1Client
,
predeploys
.
DevOptimismPortalAddr
,
wdReceipt
.
BlockNumber
,
)
require
.
NoError
(
t
,
err
)
finHeader
,
err
:=
l2Client
.
HeaderByNumber
(
context
.
Background
(),
big
.
NewInt
(
int64
(
finBlockNum
)))
require
.
NoError
(
t
,
err
)
rpcClient
,
err
:=
rpc
.
Dial
(
sys
.
Nodes
[
"sequencer"
]
.
HTTPEndpoint
())
require
.
NoError
(
t
,
err
)
proofClient
:=
withdrawals
.
NewClient
(
rpcClient
)
wParams
,
err
:=
withdrawals
.
FinalizeWithdrawalParameters
(
context
.
Background
(),
proofClient
,
wdTx
.
Hash
(),
finHeader
)
require
.
NoError
(
t
,
err
)
l1Opts
.
Value
=
big
.
NewInt
(
0
)
finTx
,
err
:=
portal
.
FinalizeWithdrawalTransaction
(
l1Opts
,
bindings
.
TypesWithdrawalTransaction
{
Nonce
:
wParams
.
Nonce
,
Sender
:
wParams
.
Sender
,
Target
:
wParams
.
Target
,
Value
:
wParams
.
Value
,
GasLimit
:
wParams
.
GasLimit
,
Data
:
wParams
.
Data
,
},
wParams
.
BlockNumber
,
wParams
.
OutputRootProof
,
wParams
.
WithdrawalProof
,
)
require
.
NoError
(
t
,
err
)
finReceipt
,
err
:=
e2eutils
.
WaitReceiptOK
(
e2eutils
.
TimeoutCtx
(
t
,
time
.
Minute
),
l1Client
,
finTx
.
Hash
())
require
.
NoError
(
t
,
err
)
wdPage
=
nil
require
.
NoError
(
t
,
e2eutils
.
WaitFor
(
e2eutils
.
TimeoutCtx
(
t
,
30
*
time
.
Second
),
100
*
time
.
Millisecond
,
func
()
(
bool
,
error
)
{
res
:=
new
(
db
.
PaginatedWithdrawals
)
err
:=
getJSON
(
makeURL
(
fmt
.
Sprintf
(
"v1/withdrawals/%s"
,
fromAddr
)),
res
)
if
err
!=
nil
{
return
false
,
err
}
if
res
.
Withdrawals
[
0
]
.
BedrockFinalizedTxHash
==
nil
{
return
false
,
nil
}
wdPage
=
res
return
true
,
nil
}))
wd
:=
wdPage
.
Withdrawals
[
0
]
require
.
Equal
(
t
,
finReceipt
.
TxHash
.
String
(),
*
wd
.
BedrockFinalizedTxHash
)
require
.
True
(
t
,
*
wd
.
BedrockFinalizedSuccess
)
wdPage
=
new
(
db
.
PaginatedWithdrawals
)
err
=
getJSON
(
makeURL
(
fmt
.
Sprintf
(
"v1/withdrawals/%s?finalized=false"
,
fromAddr
)),
wdPage
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
0
,
len
(
wdPage
.
Withdrawals
))
})
}
type
testDBParams
struct
{
Host
string
Port
uint64
User
string
Password
string
Name
string
}
func
createTestDB
(
t
*
testing
.
T
)
*
testDBParams
{
user
:=
os
.
Getenv
(
"DB_USER"
)
name
:=
fmt
.
Sprintf
(
"indexer_test_%d"
,
time
.
Now
()
.
Unix
())
dsn
:=
"postgres://"
if
user
!=
""
{
dsn
+=
user
dsn
+=
"@"
}
dsn
+=
"localhost:5432?sslmode=disable"
pg
,
err
:=
sql
.
Open
(
"postgres"
,
dsn
,
)
require
.
NoError
(
t
,
err
)
_
,
err
=
pg
.
Exec
(
"CREATE DATABASE "
+
name
)
require
.
NoError
(
t
,
err
)
t
.
Cleanup
(
func
()
{
_
,
err
=
pg
.
Exec
(
"DROP DATABASE "
+
name
)
require
.
NoError
(
t
,
err
)
pg
.
Close
()
})
return
&
testDBParams
{
Host
:
"localhost"
,
Port
:
5432
,
Name
:
name
,
User
:
user
,
}
}
func
getJSON
(
url
string
,
out
interface
{})
error
{
res
,
err
:=
http
.
Get
(
url
)
if
err
!=
nil
{
return
err
}
if
res
.
StatusCode
!=
200
{
return
fmt
.
Errorf
(
"non-200 status code %d"
,
res
.
StatusCode
)
}
defer
res
.
Body
.
Close
()
dec
:=
json
.
NewDecoder
(
res
.
Body
)
return
dec
.
Decode
(
out
)
}
indexer/sentry_log.go
deleted
100644 → 0
View file @
5a9928c0
package
indexer
import
(
"errors"
"io"
"github.com/ethereum/go-ethereum/log"
"github.com/getsentry/sentry-go"
)
var
jsonFmt
=
log
.
JSONFormat
()
// SentryStreamHandler creates a log.Handler that behaves similarly to
// log.StreamHandler, however it writes any log with severity greater than or
// equal to log.LvlError to Sentry. In that case, the passed log.Record is
// encoded using JSON rather than the default terminal output, so that it can be
// captured for debugging in the Sentry dashboard.
func
SentryStreamHandler
(
wr
io
.
Writer
,
fmtr
log
.
Format
)
log
.
Handler
{
h
:=
log
.
FuncHandler
(
func
(
r
*
log
.
Record
)
error
{
_
,
err
:=
wr
.
Write
(
fmtr
.
Format
(
r
))
// If this record's severity is log.LvlError or higher,
// serialize the record using JSON and write it to Sentry. We
// also capture the error message separately so that it's easy
// to parse what the error is in the dashboard.
//
// NOTE: The log.Lvl* constants are defined in reverse order of
// their severity, i.e. zero (log.LvlCrit) is the highest
// severity.
if
r
.
Lvl
<=
log
.
LvlError
{
sentry
.
WithScope
(
func
(
scope
*
sentry
.
Scope
)
{
scope
.
SetExtra
(
"context"
,
jsonFmt
.
Format
(
r
))
sentry
.
CaptureException
(
errors
.
New
(
r
.
Msg
))
})
}
return
err
})
return
log
.
LazyHandler
(
log
.
SyncHandler
(
h
))
}
indexer/services/l2/service.go
View file @
19e581d8
...
...
@@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer/metrics"
"github.com/ethereum-optimism/optimism/indexer/server"
"github.com/ethereum-optimism/optimism/indexer/services/query"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/prometheus/client_golang/prometheus"
"github.com/ethereum-optimism/optimism/indexer/db"
...
...
@@ -121,7 +122,7 @@ func NewService(cfg ServiceConfig) (*Service, error) {
headerSelector
:
confirmedHeaderSelector
,
metrics
:
cfg
.
Metrics
,
tokenCache
:
map
[
common
.
Address
]
*
db
.
Token
{
db
.
ETHL2Address
:
db
.
ETHL1Token
,
predeploys
.
LegacyERC20ETHAddr
:
db
.
ETHL1Token
,
},
}
service
.
wg
.
Add
(
1
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment