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
79be3e80
Unverified
Commit
79be3e80
authored
Apr 27, 2022
by
Matthew Slipper
Committed by
GitHub
Apr 27, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
indexer: Add airdrop API (#2498)
parent
ee57b82b
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
189 additions
and
23 deletions
+189
-23
cuddly-rings-reply.md
.changeset/cuddly-rings-reply.md
+5
-0
airdrop.go
go/indexer/db/airdrop.go
+13
-0
db.go
go/indexer/db/db.go
+57
-19
sql.go
go/indexer/db/sql.go
+16
-0
indexer.go
go/indexer/indexer.go
+9
-2
metrics.go
go/indexer/metrics/metrics.go
+38
-0
server.go
go/indexer/server/server.go
+7
-2
airdrop.go
go/indexer/services/airdrop.go
+44
-0
No files found.
.changeset/cuddly-rings-reply.md
0 → 100644
View file @
79be3e80
---
'
@eth-optimism/indexer'
:
minor
---
Add airdrops API
go/indexer/db/airdrop.go
0 → 100644
View file @
79be3e80
package
db
type
Airdrop
struct
{
Address
string
`json:"address"`
VoterAmount
string
`json:"voterAmount"`
MultisigSignerAmount
string
`json:"multisigSignerAmount"`
GitcoinAmount
string
`json:"gitcoinAmount"`
ActiveBridgedAmount
string
`json:"activeBridgedAmount"`
OpUserAmount
string
`json:"opUserAmount"`
OpRepeatUserAmount
string
`json:"opRepeatUserAmount"`
BonusAmount
string
`json:"bonusAmount"`
TotalAmount
string
`json:"totalAmount"`
}
go/indexer/db/db.go
View file @
79be3e80
...
...
@@ -3,6 +3,8 @@ package db
import
(
"database/sql"
"errors"
"fmt"
"strings"
l2common
"github.com/ethereum-optimism/optimism/l2geth/common"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -17,6 +19,31 @@ type Database struct {
config
string
}
// NewDatabase returns the database for the given connection string.
func
NewDatabase
(
config
string
)
(
*
Database
,
error
)
{
db
,
err
:=
sql
.
Open
(
"postgres"
,
config
)
if
err
!=
nil
{
return
nil
,
err
}
err
=
db
.
Ping
()
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
migration
:=
range
schema
{
_
,
err
=
db
.
Exec
(
migration
)
if
err
!=
nil
{
return
nil
,
err
}
}
return
&
Database
{
db
:
db
,
config
:
config
,
},
nil
}
// Close closes the database.
// NOTE: "It is rarely necessary to close a DB."
// See: https://pkg.go.dev/database/sql#Open
...
...
@@ -633,27 +660,38 @@ func (d *Database) GetIndexedL1BlockByHash(hash common.Hash) (*IndexedL1Block, e
return
block
,
nil
}
// NewDatabase returns the database for the given connection string.
func
NewDatabase
(
config
string
)
(
*
Database
,
error
)
{
db
,
err
:=
sql
.
Open
(
"postgres"
,
config
)
if
err
!=
nil
{
return
nil
,
err
const
getAirdropQuery
=
`
SELECT
address, voter_amount, multisig_signer_amount, gitcoin_amount,
active_bridged_amount, op_user_amount, op_repeat_user_amount,
bonus_amount, total_amount
FROM airdrops
WHERE address = $1
`
func
(
d
*
Database
)
GetAirdrop
(
address
common
.
Address
)
(
*
Airdrop
,
error
)
{
row
:=
d
.
db
.
QueryRow
(
getAirdropQuery
,
strings
.
ToLower
(
address
.
String
()))
if
row
.
Err
()
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"error getting airdrop: %v"
,
row
.
Err
())
}
err
=
db
.
Ping
()
if
err
!=
nil
{
return
nil
,
err
airdrop
:=
new
(
Airdrop
)
err
:=
row
.
Scan
(
&
airdrop
.
Address
,
&
airdrop
.
VoterAmount
,
&
airdrop
.
MultisigSignerAmount
,
&
airdrop
.
GitcoinAmount
,
&
airdrop
.
ActiveBridgedAmount
,
&
airdrop
.
OpUserAmount
,
&
airdrop
.
OpRepeatUserAmount
,
&
airdrop
.
BonusAmount
,
&
airdrop
.
TotalAmount
,
)
if
errors
.
Is
(
err
,
sql
.
ErrNoRows
)
{
return
nil
,
nil
}
for
_
,
migration
:=
range
schema
{
_
,
err
=
db
.
Exec
(
migration
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"error scanning airdrop: %v"
,
err
)
}
return
&
Database
{
db
:
db
,
config
:
config
,
},
nil
return
airdrop
,
nil
}
go/indexer/db/sql.go
View file @
79be3e80
...
...
@@ -107,6 +107,21 @@ CREATE UNIQUE INDEX IF NOT EXISTS l1_blocks_number ON l1_blocks(number);
CREATE UNIQUE INDEX IF NOT EXISTS l2_blocks_number ON l2_blocks(number);
`
const
createAirdropsTable
=
`
CREATE TABLE IF NOT EXISTS airdrops (
address VARCHAR(42) PRIMARY KEY,
voter_amount VARCHAR NOT NULL DEFAULT '0' CHECK(voter_amount ~ '^\d+$') ,
multisig_signer_amount VARCHAR NOT NULL DEFAULT '0' CHECK(multisig_signer_amount ~ '^\d+$'),
gitcoin_amount VARCHAR NOT NULL DEFAULT '0' CHECK(gitcoin_amount ~ '^\d+$'),
active_bridged_amount VARCHAR NOT NULL DEFAULT '0' CHECK(active_bridged_amount ~ '^\d+$'),
op_user_amount VARCHAR NOT NULL DEFAULT '0' CHECK(op_user_amount ~ '^\d+$'),
op_repeat_user_amount VARCHAR NOT NULL DEFAULT '0' CHECK(op_user_amount ~ '^\d+$'),
op_og_amount VARCHAR NOT NULL DEFAULT '0' CHECK(op_og_amount ~ '^\d+$'),
bonus_amount VARCHAR NOT NULL DEFAULT '0' CHECK(bonus_amount ~ '^\d+$'),
total_amount VARCHAR NOT NULL CHECK(voter_amount ~ '^\d+$')
)
`
var
schema
=
[]
string
{
createL1BlocksTable
,
createL2BlocksTable
,
...
...
@@ -118,4 +133,5 @@ var schema = []string{
createDepositsTable
,
createWithdrawalsTable
,
createL1L2NumberIndex
,
createAirdropsTable
,
}
go/indexer/indexer.go
View file @
79be3e80
...
...
@@ -9,6 +9,8 @@ import (
"strconv"
"time"
"github.com/ethereum-optimism/optimism/go/indexer/services"
l2rpc
"github.com/ethereum-optimism/optimism/l2geth/rpc"
"github.com/ethereum-optimism/optimism/go/indexer/metrics"
...
...
@@ -83,8 +85,10 @@ type Indexer struct {
l1IndexingService
*
l1
.
Service
l2IndexingService
*
l2
.
Service
airdropService
*
services
.
Airdrop
router
*
mux
.
Router
router
*
mux
.
Router
metrics
*
metrics
.
Metrics
}
// NewIndexer initializes the Indexer, gathering any resources
...
...
@@ -201,7 +205,9 @@ func NewIndexer(cfg Config, gitVersion string) (*Indexer, error) {
l2Client
:
l2Client
,
l1IndexingService
:
l1IndexingService
,
l2IndexingService
:
l2IndexingService
,
airdropService
:
services
.
NewAirdrop
(
db
,
m
),
router
:
mux
.
NewRouter
(),
metrics
:
m
,
},
nil
}
...
...
@@ -216,6 +222,7 @@ func (b *Indexer) Serve() error {
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
)
{
w
.
WriteHeader
(
200
)
_
,
err
:=
w
.
Write
([]
byte
(
"OK"
))
...
...
@@ -224,7 +231,7 @@ func (b *Indexer) Serve() error {
}
})
middleware
:=
server
.
LoggingMiddleware
(
log
.
New
(
"service"
,
"server"
))
middleware
:=
server
.
LoggingMiddleware
(
b
.
metrics
,
log
.
New
(
"service"
,
"server"
))
port
:=
strconv
.
FormatUint
(
b
.
cfg
.
RESTPort
,
10
)
addr
:=
fmt
.
Sprintf
(
"%s:%s"
,
b
.
cfg
.
RESTHostname
,
port
)
...
...
go/indexer/metrics/metrics.go
View file @
79be3e80
...
...
@@ -3,6 +3,8 @@ package metrics
import
(
"fmt"
"net/http"
"strconv"
"time"
l2common
"github.com/ethereum-optimism/optimism/l2geth/common"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -32,6 +34,12 @@ type Metrics struct {
CachedTokensCount
*
prometheus
.
CounterVec
HTTPRequestsCount
prometheus
.
Counter
HTTPResponsesCount
*
prometheus
.
CounterVec
HTTPRequestDurationSecs
prometheus
.
Summary
tokenAddrs
map
[
string
]
string
}
...
...
@@ -110,6 +118,27 @@ func NewMetrics(monitoredTokens map[string]string) *Metrics {
"chain"
,
}),
HTTPRequestsCount
:
promauto
.
NewCounter
(
prometheus
.
CounterOpts
{
Name
:
"http_requests_count"
,
Help
:
"How many HTTP requests this instance has seen"
,
Namespace
:
metricsNamespace
,
}),
HTTPResponsesCount
:
promauto
.
NewCounterVec
(
prometheus
.
CounterOpts
{
Name
:
"http_responses_count"
,
Help
:
"How many HTTP responses this instance has served"
,
Namespace
:
metricsNamespace
,
},
[]
string
{
"status_code"
,
}),
HTTPRequestDurationSecs
:
promauto
.
NewSummary
(
prometheus
.
SummaryOpts
{
Name
:
"http_request_duration_secs"
,
Help
:
"How long each HTTP request took"
,
Namespace
:
metricsNamespace
,
Objectives
:
map
[
float64
]
float64
{
0.5
:
0.05
,
0.9
:
0.01
,
0.95
:
0.005
,
0.99
:
0.001
},
}),
tokenAddrs
:
mts
,
}
}
...
...
@@ -176,6 +205,15 @@ func (m *Metrics) IncL2CachedTokensCount() {
m
.
CachedTokensCount
.
WithLabelValues
(
"l2"
)
.
Inc
()
}
func
(
m
*
Metrics
)
RecordHTTPRequest
()
{
m
.
HTTPRequestsCount
.
Inc
()
}
func
(
m
*
Metrics
)
RecordHTTPResponse
(
code
int
,
dur
time
.
Duration
)
{
m
.
HTTPResponsesCount
.
WithLabelValues
(
strconv
.
Itoa
(
code
))
.
Inc
()
m
.
HTTPRequestDurationSecs
.
Observe
(
float64
(
dur
)
/
float64
(
time
.
Second
))
}
func
(
m
*
Metrics
)
Serve
(
hostname
string
,
port
uint64
)
(
*
http
.
Server
,
error
)
{
mux
:=
http
.
NewServeMux
()
mux
.
Handle
(
"/metrics"
,
promhttp
.
Handler
())
...
...
go/indexer/server/server.go
View file @
79be3e80
...
...
@@ -6,6 +6,8 @@ import (
"runtime/debug"
"time"
"github.com/ethereum-optimism/optimism/go/indexer/metrics"
"github.com/ethereum/go-ethereum/log"
)
...
...
@@ -50,7 +52,7 @@ func (rw *responseWriter) WriteHeader(code int) {
}
// LoggingMiddleware logs the incoming HTTP request & its duration.
func
LoggingMiddleware
(
logger
log
.
Logger
)
func
(
http
.
Handler
)
http
.
Handler
{
func
LoggingMiddleware
(
metrics
*
metrics
.
Metrics
,
logger
log
.
Logger
)
func
(
http
.
Handler
)
http
.
Handler
{
return
func
(
next
http
.
Handler
)
http
.
Handler
{
fn
:=
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
defer
func
()
{
...
...
@@ -64,16 +66,19 @@ func LoggingMiddleware(logger log.Logger) func(http.Handler) http.Handler {
}
}()
metrics
.
RecordHTTPRequest
()
start
:=
time
.
Now
()
wrapped
:=
wrapResponseWriter
(
w
)
next
.
ServeHTTP
(
wrapped
,
r
)
dur
:=
time
.
Since
(
start
)
logger
.
Info
(
"served request"
,
"status"
,
wrapped
.
status
,
"method"
,
r
.
Method
,
"path"
,
r
.
URL
.
EscapedPath
(),
"duration"
,
time
.
Since
(
start
)
,
"duration"
,
dur
,
)
metrics
.
RecordHTTPResponse
(
wrapped
.
status
,
dur
)
}
return
http
.
HandlerFunc
(
fn
)
...
...
go/indexer/services/airdrop.go
0 → 100644
View file @
79be3e80
package
services
import
(
"net/http"
"github.com/ethereum-optimism/optimism/go/indexer/db"
"github.com/ethereum-optimism/optimism/go/indexer/metrics"
"github.com/ethereum-optimism/optimism/go/indexer/server"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/gorilla/mux"
)
var
airdropLogger
=
log
.
New
(
"service"
,
"airdrop"
)
type
Airdrop
struct
{
db
*
db
.
Database
metrics
*
metrics
.
Metrics
}
func
NewAirdrop
(
db
*
db
.
Database
,
metrics
*
metrics
.
Metrics
)
*
Airdrop
{
return
&
Airdrop
{
db
:
db
,
metrics
:
metrics
,
}
}
func
(
a
*
Airdrop
)
GetAirdrop
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
vars
:=
mux
.
Vars
(
r
)
address
:=
vars
[
"address"
]
airdrop
,
err
:=
a
.
db
.
GetAirdrop
(
common
.
HexToAddress
(
address
))
if
err
!=
nil
{
airdropLogger
.
Error
(
"db error getting airdrop"
,
"err"
,
err
)
server
.
RespondWithError
(
w
,
http
.
StatusInternalServerError
,
"database error"
)
return
}
if
airdrop
==
nil
{
server
.
RespondWithError
(
w
,
http
.
StatusNotFound
,
"airdrop not found"
)
return
}
server
.
RespondWithJSON
(
w
,
http
.
StatusOK
,
airdrop
)
}
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