From 191cff06efddb3a0784c3176f2ef81820431063e Mon Sep 17 00:00:00 2001 From: bayge Date: Tue, 25 Jun 2024 17:41:07 +0930 Subject: [PATCH] Support Sentry, pull bloom filter --- cmd/faucet.superposition/Makefile | 3 -- cmd/faucet.superposition/main.go | 18 +++---- cmd/graphql.ethereum/main.go | 19 ++++--- cmd/ingestor.logs.ethereum/func.go | 14 ++--- cmd/ingestor.logs.ethereum/main.go | 12 ++--- cmd/snapshot.ethereum/main.go | 14 ++--- go.mod | 5 ++ go.sum | 16 +++++- lib/config/config.go | 12 ++--- lib/features/features.go | 14 +++-- lib/setup/setup.go | 72 ++++++++++++++++++++++--- pkg/utils/.gitignore | 1 - pkg/utils/Makefile | 3 -- pkg/utils/bloom-filter.go | 80 ---------------------------- pkg/utils/bloom-filter_test.go | 84 ------------------------------ 15 files changed, 140 insertions(+), 227 deletions(-) delete mode 100644 pkg/utils/.gitignore delete mode 100644 pkg/utils/Makefile delete mode 100644 pkg/utils/bloom-filter.go delete mode 100644 pkg/utils/bloom-filter_test.go diff --git a/cmd/faucet.superposition/Makefile b/cmd/faucet.superposition/Makefile index 32b5d09b..34f93140 100644 --- a/cmd/faucet.superposition/Makefile +++ b/cmd/faucet.superposition/Makefile @@ -5,9 +5,6 @@ include ../golang.mk lambda: bootstrap.zip -stakers.json: ../../config/stakers.json - @cp ../../config/stakers.json stakers.json - bootstrap: faucet.superposition @cp faucet.superposition bootstrap diff --git a/cmd/faucet.superposition/main.go b/cmd/faucet.superposition/main.go index 19d2f32d..437d7769 100644 --- a/cmd/faucet.superposition/main.go +++ b/cmd/faucet.superposition/main.go @@ -6,13 +6,12 @@ import ( "context" "crypto/ecdsa" _ "embed" - "log" "net/http" "os" "github.com/fluidity-money/long.so/lib/config" "github.com/fluidity-money/long.so/lib/features" - _ "github.com/fluidity-money/long.so/lib/setup" + "github.com/fluidity-money/long.so/lib/setup" "github.com/fluidity-money/long.so/cmd/faucet.superposition/graph" "github.com/fluidity-money/long.so/cmd/faucet.superposition/lib/faucet" @@ -63,35 +62,36 @@ func (m requestMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func main() { + defer setup.Flush() config := config.Get() db, err := gorm.Open(postgres.Open(config.TimescaleUrl), &gorm.Config{ DisableAutomaticPing: true, Logger: gormLogger.Default.LogMode(gormLogger.Silent), }) if err != nil { - log.Fatalf("database open: %v", err) + setup.Exitf("database open: %v", err) } // Get the private key to use to make transactions to the faucet with later. key_ := os.Getenv(EnvPrivateKey) if key_ == "" { - log.Fatalf("%#v unset", EnvPrivateKey) + setup.Exitf("%#v unset", EnvPrivateKey) } key, err := ethCrypto.HexToECDSA(key_) if err != nil { - log.Fatalf("private key: %v", err) + setup.Exitf("private key: %v", err) } faucetAddr := ethCommon.HexToAddress(os.Getenv(EnvFaucetAddr)) senderPub, _ := key.Public().(*ecdsa.PublicKey) // Should be fine. senderAddr := ethCrypto.PubkeyToAddress(*senderPub) geth, err := ethclient.Dial(config.GethUrl) if err != nil { - log.Fatalf("geth open: %v", err) + setup.Exitf("geth open: %v", err) } defer geth.Close() // Get the chain id for sending out requests to the faucet. chainId, err := geth.ChainID(context.Background()) if err != nil { - log.Fatalf("chain id: %v", err) + setup.Exitf("chain id: %v", err) } // Start the sender in another Go routine to send batch requests // out of the SPN (gas) token. @@ -113,13 +113,13 @@ func main() { lambda.Start(httpadapter.New(http.DefaultServeMux).ProxyWithContext) case "http": err := http.ListenAndServe(os.Getenv(EnvListenAddr), nil) - log.Fatalf( // This should only return if there's an error. + setup.Exitf( // This should only return if there's an error. "err listening, %#v not set?: %v", EnvListenAddr, err, ) default: - log.Fatalf( + setup.Exitf( "unexpected listen type: %#v, use either (lambda|http) for SPN_LISTEN_BACKEND", typ, ) diff --git a/cmd/graphql.ethereum/main.go b/cmd/graphql.ethereum/main.go index ca98dc4b..88b2f03a 100644 --- a/cmd/graphql.ethereum/main.go +++ b/cmd/graphql.ethereum/main.go @@ -3,13 +3,12 @@ package main //go:generate go run github.com/99designs/gqlgen generate import ( - "log" "net/http" "os" "github.com/fluidity-money/long.so/lib/config" "github.com/fluidity-money/long.so/lib/features" - _ "github.com/fluidity-money/long.so/lib/setup" + "github.com/fluidity-money/long.so/lib/setup" "github.com/fluidity-money/long.so/cmd/graphql.ethereum/graph" @@ -20,7 +19,7 @@ import ( "gorm.io/driver/postgres" "gorm.io/gorm" - gormLogger "gorm.io/gorm/logger" + gormSlog "github.com/orandin/slog-gorm" "github.com/aws/aws-lambda-go/lambda" @@ -46,17 +45,18 @@ func (m corsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { } func main() { + defer setup.Flush() config := config.Get() db, err := gorm.Open(postgres.Open(config.TimescaleUrl), &gorm.Config{ DisableAutomaticPing: true, - Logger: gormLogger.Default.LogMode(gormLogger.Silent), + Logger: gormSlog.New(), // Use default slog }) if err != nil { - log.Fatalf("database open: %v", err) + setup.Exitf("database open: %v", err) } geth, err := ethclient.Dial(config.GethUrl) if err != nil { - log.Fatalf("geth open: %v", err) + setup.Exitf("geth open: %v", err) } defer geth.Close() srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{ @@ -74,12 +74,15 @@ func main() { lambda.Start(httpadapter.New(http.DefaultServeMux).ProxyWithContext) case "http": err := http.ListenAndServe(os.Getenv(EnvListenAddr), nil) - log.Fatalf( // This should only return if there's an error. + setup.Exitf( // This should only return if there's an error. "err listening, %#v not set?: %v", EnvListenAddr, err, ) default: - log.Fatalf("unexpected listen type: %#v, use either (lambda|http) for SPN_LISTEN_BACKEND", typ) + setup.Exitf( + "unexpected listen type: %#v, use either (lambda|http) for SPN_LISTEN_BACKEND", + typ, + ) } } diff --git a/cmd/ingestor.logs.ethereum/func.go b/cmd/ingestor.logs.ethereum/func.go index 95adbd3e..0259751c 100644 --- a/cmd/ingestor.logs.ethereum/func.go +++ b/cmd/ingestor.logs.ethereum/func.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "fmt" - "log" "log/slog" "math/big" "time" @@ -13,6 +12,7 @@ import ( "github.com/fluidity-money/long.so/lib/events/erc20" "github.com/fluidity-money/long.so/lib/events/seawater" "github.com/fluidity-money/long.so/lib/config" + "github.com/fluidity-money/long.so/lib/setup" "github.com/fluidity-money/long.so/lib/features" "github.com/fluidity-money/long.so/lib/heartbeat" @@ -59,7 +59,7 @@ func IngestPolling(f features.F, c *ethclient.Client, db *gorm.DB, ingestorPagin // Start by finding the latest block number. from, err := getLastBlockCheckpointed(db) if err != nil { - log.Fatalf("failed to get the last block checkpoint: %v", err) + setup.Exitf("failed to get the last block checkpoint: %v", err) } to := from + ingestorPagination from++ // Increase the starting block by 1 so we always get the next block. @@ -87,7 +87,7 @@ func IngestBlockRange(f features.F, c *ethclient.Client, db *gorm.DB, seawaterAd Topics: FilterTopics, }) if err != nil { - log.Fatalf("failed to filter logs: %v", err) + setup.Exitf("failed to filter logs: %v", err) } err = db.Transaction(func(db *gorm.DB) error { wasChanged := false @@ -111,7 +111,7 @@ func IngestBlockRange(f features.F, c *ethclient.Client, db *gorm.DB, seawaterAd return nil }) if err != nil { - log.Fatalf("failed to ingest logs into db: %v", err) + setup.Exitf("failed to ingest logs into db: %v", err) } } @@ -129,7 +129,7 @@ func IngestWebsocket(f features.F, c *ethclient.Client, db *gorm.DB, seawaterAdd go func() { subscription, err := c.SubscribeFilterLogs(context.Background(), filter, logs) if err != nil { - log.Fatalf("eth log subscription: %v", err) + setup.Exitf("eth log subscription: %v", err) } err = <-subscription.Err() errors <- err @@ -137,7 +137,7 @@ func IngestWebsocket(f features.F, c *ethclient.Client, db *gorm.DB, seawaterAdd for { select { case err := <-errors: - log.Fatalf("subscription error: %v", err) + setup.Exitf("subscription error: %v", err) case l := <-logs: // Figure out what kind of log this is, and then insert it into the database. err := db.Transaction(func(db *gorm.DB) error { @@ -151,7 +151,7 @@ func IngestWebsocket(f features.F, c *ethclient.Client, db *gorm.DB, seawaterAdd return nil }) if err != nil { - log.Fatalf("failed to handle a database log: %v", err) + setup.Exitf("failed to handle a database log: %v", err) } heartbeat.Pulse() // Report that we're alive. } diff --git a/cmd/ingestor.logs.ethereum/main.go b/cmd/ingestor.logs.ethereum/main.go index 1f28462a..653af7ab 100644 --- a/cmd/ingestor.logs.ethereum/main.go +++ b/cmd/ingestor.logs.ethereum/main.go @@ -1,12 +1,11 @@ package main import ( - "log" "log/slog" "os" "strconv" - _ "github.com/fluidity-money/long.so/lib/setup" + "github.com/fluidity-money/long.so/lib/setup" "github.com/fluidity-money/long.so/lib/config" "github.com/fluidity-money/long.so/lib/features" @@ -36,17 +35,18 @@ const ( ) func main() { + defer setup.Flush() config := config.Get() db, err := gorm.Open(postgres.Open(config.TimescaleUrl), &gorm.Config{ Logger: gormLogger.Default.LogMode(gormLogger.Silent), }) if err != nil { - log.Fatalf("opening postgres: %v", err) + setup.Exitf("opening postgres: %v", err) } // Start to ingest block headers by connecting to the websocket given. c, err := ethclient.Dial(config.GethUrl) if err != nil { - log.Fatalf("websocket dial: %v", err) + setup.Exitf("websocket dial: %v", err) } defer c.Close() /* Ingestor-specific configuration. */ @@ -63,7 +63,7 @@ func main() { var err error ingestorPagination, err = strconv.ParseUint(ingestorPagination_, 10, 64) if err != nil { - log.Fatalf( + setup.Exitf( "failed to parse pagination block increase, string is %#v: %v", ingestorPagination_, err, @@ -80,7 +80,7 @@ func main() { } else { i, err := strconv.ParseInt(ingestorPollWait_, 10, 32) if err != nil { - log.Fatalf( + setup.Exitf( "failed to parse pagination poll wait, string is %#v: %v", ingestorPollWait_, err, diff --git a/cmd/snapshot.ethereum/main.go b/cmd/snapshot.ethereum/main.go index e39fc0ab..9653609d 100644 --- a/cmd/snapshot.ethereum/main.go +++ b/cmd/snapshot.ethereum/main.go @@ -5,14 +5,13 @@ import ( "context" "fmt" "io" - "log" "log/slog" "math/big" "net/http" "github.com/fluidity-money/long.so/lib/config" "github.com/fluidity-money/long.so/lib/math" - _ "github.com/fluidity-money/long.so/lib/setup" + "github.com/fluidity-money/long.so/lib/setup" "github.com/fluidity-money/long.so/lib/types" "github.com/fluidity-money/long.so/lib/types/seawater" @@ -30,12 +29,13 @@ type PoolDetails struct { } func main() { + defer setup.Flush() config := config.Get() db, err := gorm.Open(postgres.Open(config.TimescaleUrl), &gorm.Config{ Logger: gormLogger.Default.LogMode(gormLogger.Silent), }) if err != nil { - log.Fatalf("database open: %v", err) + setup.Exitf("database open: %v", err) } slog.Debug("about to make another lookup") // Get every active position in the database, including the pools. @@ -45,7 +45,7 @@ func main() { Scan(&positions). Error if err != nil { - log.Fatalf("seawater positions scan: %v", err) + setup.Exitf("seawater positions scan: %v", err) } slog.Debug("positions we're about to scan", "positions", positions) var poolDetails []PoolDetails @@ -55,7 +55,7 @@ func main() { Scan(&poolDetails). Error if err != nil { - log.Fatalf("scan positions: %v", err) + setup.Exitf("scan positions: %v", err) } slog.Debug("pools we're about to scan", "pools", poolDetails) poolMap := make(map[string]PoolDetails, len(poolDetails)) @@ -80,7 +80,7 @@ func main() { // Makes multiple requests if the request size exceeds the current restriction. resps, err := reqPositions(context.Background(), config.GethUrl, d, httpPost) if err != nil { - log.Fatalf("positions request: %v", err) + setup.Exitf("positions request: %v", err) } var ( ids = make([]int, len(positions)) @@ -130,7 +130,7 @@ func main() { return } if err := storePositions(db, ids, amount0s, amount1s); err != nil { - log.Fatalf("store positions: %v", err) + setup.Exitf("store positions: %v", err) } } diff --git a/go.mod b/go.mod index 311b87e0..30c9672a 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,10 @@ require ( github.com/aws/aws-lambda-go v1.47.0 github.com/awslabs/aws-lambda-go-api-proxy v0.16.2 github.com/ethereum/go-ethereum v1.14.5 + github.com/getsentry/sentry-go v0.22.0 github.com/lib/pq v1.10.9 + github.com/orandin/slog-gorm v1.3.2 + github.com/samber/slog-sentry/v2 v2.5.0 github.com/stretchr/testify v1.9.0 github.com/vektah/gqlparser/v2 v2.5.16 gorm.io/driver/postgres v1.5.9 @@ -43,6 +46,8 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/samber/lo v1.38.1 // indirect + github.com/samber/slog-common v0.16.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sosodev/duration v1.3.1 // indirect github.com/supranational/blst v0.3.11 // indirect diff --git a/go.sum b/go.sum index 26a35297..dcb43649 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,10 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.22.0 h1:XNX9zKbv7baSEI65l+H1GEJgSeIC1c7EN5kluWaP6dM= +github.com/getsentry/sentry-go v0.22.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -160,6 +162,10 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/orandin/slog-gorm v1.3.2 h1:C0lKDQPAx/pF+8K2HL7bdShPwOEJpPM0Bn80zTzxU1g= +github.com/orandin/slog-gorm v1.3.2/go.mod h1:MoZ51+b7xE9lwGNPYEhxcUtRNrYzjdcKvA8QXQQGEPA= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -180,6 +186,12 @@ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samber/slog-common v0.16.0 h1:2/t1EcFd1Ru77mh2ab+8B6NBHnEXsBBHtOJc7PSH0aI= +github.com/samber/slog-common v0.16.0/go.mod h1:Qjrfhwk79XiCIhBj8+jTq1Cr0u9rlWbjawh3dWXzaHk= +github.com/samber/slog-sentry/v2 v2.5.0 h1:aY5DdmTJF/HibevGWnIGYpxB3zeryPxJkMCfxbfBiRM= +github.com/samber/slog-sentry/v2 v2.5.0/go.mod h1:B3Q9VVYIBhQ1oqFHpPvtam3wIzn5eUpVBEqcLImxfjQ= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= diff --git a/lib/config/config.go b/lib/config/config.go index f505cfe5..e22eb3e1 100644 --- a/lib/config/config.go +++ b/lib/config/config.go @@ -4,11 +4,11 @@ package config import ( - "log" "os" "strings" - _ "github.com/fluidity-money/long.so/lib/setup" + "github.com/fluidity-money/long.so/lib/setup" + "github.com/fluidity-money/long.so/lib/types" ) @@ -24,19 +24,19 @@ func Get() C { /* Global RPC configuration. */ gethUrl := os.Getenv("SPN_GETH_URL") if gethUrl == "" { - log.Fatal("SPN_GETH_URL not set") + setup.Exitf("SPN_GETH_URL not set") } timescaleUrl := os.Getenv("SPN_TIMESCALE") if timescaleUrl == "" { - log.Fatal("SPN_TIMESCALE not set") + setup.Exitf("SPN_TIMESCALE not set") } seawaterAddr := strings.ToLower(os.Getenv("SPN_SEAWATER_ADDR")) if seawaterAddr == "" { - log.Fatal("SPN_SEAWATER_ADDR not set") + setup.Exitf("SPN_SEAWATER_ADDR not set") } fusdcAddr := strings.ToLower(os.Getenv("SPN_FUSDC_ADDR")) if fusdcAddr == "" { - log.Fatal("SPN_FUSDC_ADDR not set") + setup.Exitf("SPN_FUSDC_ADDR not set") } return C{ GethUrl: gethUrl, diff --git a/lib/features/features.go b/lib/features/features.go index a1b0ab09..e42165fe 100644 --- a/lib/features/features.go +++ b/lib/features/features.go @@ -8,11 +8,12 @@ package features import ( "bytes" "encoding/json" - "log" "log/slog" "net/http" "os" "strings" + + "github.com/fluidity-money/long.so/lib/setup" ) // EnvFeatures to enable at runtime from env (optionally) @@ -32,7 +33,10 @@ type F struct { // or use EnvFeatures. func Get() F { f := get() - slog.Debug("enabled features", "features", f.enabled, "everything enabled?", f.everything) + slog.Debug("enabled features", + "features", f.enabled, + "everything enabled?", f.everything, + ) return f } @@ -61,17 +65,17 @@ func get() F { func getFromBucket() F { r, err := http.Get(FeaturesBucket) if err != nil { - log.Fatalf("features bucket: get: %v", err) + setup.Exitf("features bucket: get: %v", err) } defer r.Body.Close() var enabled map[string]bool var buf bytes.Buffer // copy for logging if something goes wrong here. if _, err := buf.ReadFrom(r.Body); err != nil { - log.Fatalf("features bucket: draining: %v", err) + setup.Exitf("features bucket: draining: %v", err) } buf2 := buf if err := json.NewDecoder(&buf).Decode(&enabled); err != nil { - log.Fatalf("features bucket: decoding %#v: %v", buf2.String(), err) + setup.Exitf("features bucket: decoding %#v: %v", buf2.String(), err) } return F{ everything: false, diff --git a/lib/setup/setup.go b/lib/setup/setup.go index 1b929690..c8da5894 100644 --- a/lib/setup/setup.go +++ b/lib/setup/setup.go @@ -4,12 +4,25 @@ package setup import ( - "os" + "log" "log/slog" + "os" + "runtime/debug" + "strings" + "fmt" + "time" + + "github.com/getsentry/sentry-go" + slogsentry "github.com/samber/slog-sentry/v2" ) -// EnvDebug for enabling debug printing of messages. -const EnvDebug = "SPN_DEBUG" +const ( + // EnvDebug for enabling debug printing of messages. + EnvDebug = "SPN_DEBUG" + + // EnvSentryDsn to use for logging sentry-related messages. + EnvSentryDsn = "SPN_SENTRY_DSN" +) func init() { // Set up the logging to print JSON blobs. @@ -17,7 +30,54 @@ func init() { if os.Getenv(EnvDebug) != "" { logLevel = slog.LevelDebug } - slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ - Level: logLevel, - }))) + // Set up Sentry, if it's enabled. + dsn := os.Getenv(EnvSentryDsn) + if dsn != "" { + err := sentry.Init(sentry.ClientOptions{ + Dsn: dsn, + EnableTracing: false, + }) + if err != nil { + panic(fmt.Sprintf("failed to set up sentry: %v", err)) + } + } + var logger *slog.Logger + if dsn != "" { // DSN being set means we're using Sentry. + slogSentryOpts := slogsentry.Option{Level: logLevel}.NewSentryHandler() + logger = slog.New(slogSentryOpts) + } else { + logger = slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ + Level: logLevel, + })) + } + // Find the commit hash (taken straight from + // https:icinga.com/blog/2022/05/25/embedding-git-commit-information-in-go-binaries/) + var revision string + if info, ok := debug.ReadBuildInfo(); ok { + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + revision = setting.Value + break + } + } + } + logger. + With("revision", revision). + With("environment", "backend"). + With("command line", strings.Join(os.Args, ",")). + With("is debug", logLevel == slog.LevelDebug) + slog.SetDefault(logger) +} + +func Flush() { + sentry.Flush(2 * time.Second) +} + +func Exit() { + Flush() + os.Exit(1) +} +func Exitf(s string, f ...any) { + log.Printf(s, f...) + Exit() } diff --git a/pkg/utils/.gitignore b/pkg/utils/.gitignore deleted file mode 100644 index b1bad107..00000000 --- a/pkg/utils/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bloom-filter diff --git a/pkg/utils/Makefile b/pkg/utils/Makefile deleted file mode 100644 index 9fdf3da7..00000000 --- a/pkg/utils/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -bloom-filter: bloom-filter.go - @go build bloom-filter.go diff --git a/pkg/utils/bloom-filter.go b/pkg/utils/bloom-filter.go deleted file mode 100644 index 05a7d7c6..00000000 --- a/pkg/utils/bloom-filter.go +++ /dev/null @@ -1,80 +0,0 @@ -// bloom-filter: using the addresses given as stdin, create a bloom -// filter, and print it in it's hex form to stdout with a contract -// prelude. - -package main - -import ( - "bufio" - "encoding/binary" - "io" - "log" - "math/big" - "os" - - ethCommon "github.com/ethereum/go-ethereum/common" - ethCrypto "github.com/ethereum/go-ethereum/crypto" -) - -const MaxContractSizeMinPrelude = 24576 - 1 - -var maxContractSizeMinPrelude = new(big.Int).SetInt64(MaxContractSizeMinPrelude) - -func main() { - r := bufio.NewScanner(os.Stdin) - r.Split(bufio.ScanLines) - bloom := new(big.Int) - for i := 0; r.Scan(); i++ { - t := r.Text() - if !ethCommon.IsHexAddress(t) { - log.Fatalf("failed to read address %#v at line %v", t, i+1) - } - a := ethCommon.HexToAddress(t) - addToBloom(bloom, a) - } - switch err := r.Err(); err { - case io.EOF, nil: - // Do nothing - default: - log.Fatalf("Failed to read line: %v", err) - } - log.Printf("%x", createContract(bloom)) -} - -func createContract(bloom *big.Int) []byte { - b := bloom.Bytes() - l := make([]byte, 2) - // Include the STOP opcode before the blob. - binary.BigEndian.PutUint16(l, uint16(len(b) + 1)) - return append( - []byte{0x61}, - append( - l, - append( - // (0x00 is the STOP opcode) - []byte{0x3d, 0x81, 0x60, 0x0a, 0x3d, 0x39, 0xf3, 0x00}, - b..., - )..., - )..., - ) -} - -func addToBloom(bloom *big.Int, addr ethCommon.Address) { - pos := new(big.Int) - pos.SetBytes(ethCrypto.Keccak256(encodePacked(addr))) - pos.Mod(pos, maxContractSizeMinPrelude) - bloom.SetBit(bloom, int(pos.Int64()), 1) -} - -func bloomContains(b *big.Int, addr ethCommon.Address) bool { - pos := new(big.Int).SetBytes(ethCrypto.Keccak256(encodePacked(addr))) - pos.Mod(pos, maxContractSizeMinPrelude) - if b.Bit(int(pos.Int64())) == 0 { - return false - } - return true -} - -func encodePacked(a ethCommon.Address) []byte { - return ethCommon.LeftPadBytes(a.Bytes(), 32) -} diff --git a/pkg/utils/bloom-filter_test.go b/pkg/utils/bloom-filter_test.go deleted file mode 100644 index 534710f7..00000000 --- a/pkg/utils/bloom-filter_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "math/big" - "math/rand" - "encoding/hex" - "testing" - - "github.com/stretchr/testify/assert" - - ethCommon "github.com/ethereum/go-ethereum/common" -) - -// TestAddToBloom by testing if we're below the error rate that makes -// sense in the product context (5%.) -func TestAddToBloom(t *testing.T) { - elems := 875 - addresses := make([]ethCommon.Address, elems) - bloom := new(big.Int) - for i := 0; i < len(addresses); i++ { - a := newAddr() - addresses[i] = a - addToBloom(bloom, a) - } - // Test that we can validate all the addresses. - for _, a := range addresses { - assert.True(t, bloomContains(bloom, a)) - } - // Test that the amount of probabilities is in line. - attempts := 1_000_000 - hits := 0 - for i := 0; i < attempts; i++ { - if bloomContains(bloom, newAddr()) { - hits++ - } - } - // Check! - occurances := new(big.Rat).SetInt64(int64(hits)) - occurances.Quo(occurances, new(big.Rat).SetInt64(int64(attempts))) - prob, _ := new(big.Rat).SetString("0.05") - assert.Falsef(t, - //occurances > prob - occurances.Cmp(prob) > 0, - "bloom filter not correct! hits %v, attempts %v, occurances %v, prob %v", - hits, - attempts, - occurances.FloatString(16), - prob.FloatString(16), - ) -} - -func TestCreateContract(t *testing.T) { - b := new(big.Int) - stakers := []string{ - "0x48d2b2167cf226a965945162162a15cffc94c5dc", - "0xbda286835101a2dc37f95c4baa8f0b96fdfbe7a4", - "0x59f423153e5f1553d0712854ac082c3e37527b45", - "0x7e00d48be78fb458fd4aa4df6d2182b31a055ce1", - "0x4433d7c2b98b7478faac7ef96977539d8fed8327", - "0xd6e41a2fc219ee8929f6b3ba779f9d745d6257b2", - "0x09fe56d0f725dbce9c53eaf0d3c37e554806d532", - "0xbe3c4af0ca362a805a22244cb5ca61da48c19a41", - "0xe0b35c1e847749be1a6aef47570aef3f6d2c8c38", - "0xbf8047bd6fc06d5b84f7fc4605a48234529fd417", - } - for _, a := range stakers { - addToBloom(b, ethCommon.HexToAddress(a)) - } - c := createContract(b) - x,err := hex.DecodeString("610b923d81600a3d39f300400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000") - if err != nil { - t.Fatalf("failed to decode: %v", err) - } - assert.Equal(t, x ,c) -} - -func newAddr() ethCommon.Address { - b := make([]byte, 32) - _, err := rand.Read(b) - if err != nil { - panic(err) - } - return ethCommon.BytesToAddress(b) -}