228 lines
6.5 KiB
Go
228 lines
6.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/health"
|
|
"github.com/wormhole-foundation/wormhole-explorer/common/logger"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/builder"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/config"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/http/infrastructure"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/internal/ankr"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/internal/db"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/processor"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/storage"
|
|
"github.com/wormhole-foundation/wormhole-explorer/contract-watcher/watcher"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.uber.org/ratelimit"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type exitCode int
|
|
|
|
func handleExit() {
|
|
if r := recover(); r != nil {
|
|
if e, ok := r.(exitCode); ok {
|
|
os.Exit(int(e))
|
|
}
|
|
panic(r) // not an Exit, bubble up
|
|
}
|
|
}
|
|
|
|
type watchersConfig struct {
|
|
evms []config.WatcherBlockchainAddresses
|
|
solana *config.WatcherBlockchain
|
|
terra *config.WatcherBlockchain
|
|
aptos *config.WatcherBlockchain
|
|
oasis *config.WatcherBlockchainAddresses
|
|
moonbeam *config.WatcherBlockchainAddresses
|
|
rateLimit rateLimitConfig
|
|
}
|
|
|
|
type rateLimitConfig struct {
|
|
evm int
|
|
solana int
|
|
terra int
|
|
aptos int
|
|
oasis int
|
|
moonbeam int
|
|
}
|
|
|
|
func Run() {
|
|
|
|
defer handleExit()
|
|
rootCtx, rootCtxCancel := context.WithCancel(context.Background())
|
|
|
|
config, err := config.New(rootCtx)
|
|
if err != nil {
|
|
log.Fatal("Error creating config", err)
|
|
}
|
|
|
|
logger := logger.New("wormhole-explorer-contract-watcher", logger.WithLevel(config.LogLevel))
|
|
|
|
logger.Info("Starting wormhole-explorer-contract-watcher ...")
|
|
|
|
//setup DB connection
|
|
db, err := db.New(rootCtx, logger, config.MongoURI, config.MongoDatabase)
|
|
if err != nil {
|
|
logger.Fatal("failed to connect MongoDB", zap.Error(err))
|
|
}
|
|
|
|
// get health check functions.
|
|
healthChecks, err := newHealthChecks(rootCtx, db.Database)
|
|
if err != nil {
|
|
logger.Fatal("failed to create health checks", zap.Error(err))
|
|
}
|
|
|
|
// create repositories
|
|
repo := storage.NewRepository(db.Database, logger)
|
|
|
|
// create watchers
|
|
watchers := newWatchers(config, repo, logger)
|
|
|
|
//create processor
|
|
processor := processor.NewProcessor(watchers, logger)
|
|
processor.Start(rootCtx)
|
|
|
|
// create and start server.
|
|
server := infrastructure.NewServer(logger, config.Port, config.PprofEnabled, healthChecks...)
|
|
server.Start()
|
|
|
|
logger.Info("Started wormhole-explorer-contract-watcher")
|
|
|
|
// Waiting for signal
|
|
sigterm := make(chan os.Signal, 1)
|
|
signal.Notify(sigterm, syscall.SIGINT, syscall.SIGTERM)
|
|
select {
|
|
case <-rootCtx.Done():
|
|
logger.Warn("Terminating with root context cancelled.")
|
|
case signal := <-sigterm:
|
|
logger.Info("Terminating with signal.", zap.String("signal", signal.String()))
|
|
}
|
|
|
|
logger.Info("root context cancelled, exiting...")
|
|
rootCtxCancel()
|
|
|
|
logger.Info("Closing processor ...")
|
|
processor.Close()
|
|
logger.Info("Closing database connections ...")
|
|
db.Close()
|
|
logger.Info("Closing Http server ...")
|
|
server.Stop()
|
|
logger.Info("Finished wormhole-explorer-contract-watcher")
|
|
}
|
|
|
|
func newHealthChecks(ctx context.Context, db *mongo.Database) ([]health.Check, error) {
|
|
return []health.Check{health.Mongo(db)}, nil
|
|
}
|
|
|
|
func newWatchers(config *config.ServiceConfiguration, repo *storage.Repository, logger *zap.Logger) []watcher.ContractWatcher {
|
|
var watchers *watchersConfig
|
|
switch config.P2pNetwork {
|
|
case domain.P2pMainNet:
|
|
watchers = newWatchersForMainnet()
|
|
case domain.P2pTestNet:
|
|
watchers = newWatchersForTestnet()
|
|
default:
|
|
watchers = &watchersConfig{}
|
|
}
|
|
|
|
result := make([]watcher.ContractWatcher, 0)
|
|
|
|
// add evm watchers
|
|
evmLimiter := ratelimit.New(watchers.rateLimit.evm, ratelimit.Per(time.Second))
|
|
ankrClient := ankr.NewAnkrSDK(config.AnkrUrl, evmLimiter)
|
|
for _, w := range watchers.evms {
|
|
params := watcher.EVMParams{ChainID: w.ChainID, Blockchain: w.Name, SizeBlocks: w.SizeBlocks,
|
|
WaitSeconds: w.WaitSeconds, InitialBlock: w.InitialBlock, MethodsByAddress: w.MethodsByAddress}
|
|
result = append(result, watcher.NewEVMWatcher(ankrClient, repo, params, logger))
|
|
}
|
|
|
|
// add solana watcher
|
|
if watchers.solana != nil {
|
|
solanWatcher := builder.CreateSolanaWatcher(watchers.rateLimit.solana, config.SolanaUrl, *watchers.solana, logger, repo)
|
|
result = append(result, solanWatcher)
|
|
}
|
|
|
|
// add terra watcher
|
|
if watchers.terra != nil {
|
|
terraWatcher := builder.CreateTerraWatcher(watchers.rateLimit.terra, config.TerraUrl, *watchers.terra, logger, repo)
|
|
result = append(result, terraWatcher)
|
|
}
|
|
|
|
// add aptos watcher
|
|
if watchers.aptos != nil {
|
|
aptosWatcher := builder.CreateAptosWatcher(watchers.rateLimit.aptos, config.AptosUrl, *watchers.aptos, logger, repo)
|
|
result = append(result, aptosWatcher)
|
|
}
|
|
|
|
// add oasis watcher
|
|
if watchers.oasis != nil {
|
|
oasisWatcher := builder.CreateOasisWatcher(watchers.rateLimit.oasis, config.OasisUrl, *watchers.oasis, logger, repo)
|
|
result = append(result, oasisWatcher)
|
|
}
|
|
|
|
// add moonbeam watcher
|
|
if watchers.moonbeam != nil {
|
|
moonbeamWatcher := builder.CreateMoonbeamWatcher(watchers.rateLimit.moonbeam, config.MoonbeamUrl, *watchers.moonbeam, logger, repo)
|
|
result = append(result, moonbeamWatcher)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func newWatchersForMainnet() *watchersConfig {
|
|
return &watchersConfig{
|
|
evms: []config.WatcherBlockchainAddresses{
|
|
config.ETHEREUM_MAINNET,
|
|
config.POLYGON_MAINNET,
|
|
config.BSC_MAINNET,
|
|
config.FANTOM_MAINNET,
|
|
config.AVALANCHE_MAINNET,
|
|
},
|
|
solana: &config.SOLANA_MAINNET,
|
|
terra: &config.TERRA_MAINNET,
|
|
aptos: &config.APTOS_MAINNET,
|
|
oasis: &config.OASIS_MAINNET,
|
|
moonbeam: &config.MOONBEAM_MAINNET,
|
|
rateLimit: rateLimitConfig{
|
|
evm: 1000,
|
|
solana: 3,
|
|
terra: 10,
|
|
aptos: 3,
|
|
oasis: 3,
|
|
moonbeam: 5,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newWatchersForTestnet() *watchersConfig {
|
|
return &watchersConfig{
|
|
evms: []config.WatcherBlockchainAddresses{
|
|
config.ETHEREUM_TESTNET,
|
|
config.POLYGON_TESTNET,
|
|
config.BSC_TESTNET,
|
|
config.FANTOM_TESTNET,
|
|
config.AVALANCHE_TESTNET,
|
|
},
|
|
solana: &config.SOLANA_TESTNET,
|
|
aptos: &config.APTOS_TESTNET,
|
|
oasis: &config.OASIS_TESTNET,
|
|
moonbeam: &config.MOONBEAM_TESTNET,
|
|
rateLimit: rateLimitConfig{
|
|
evm: 10,
|
|
solana: 2,
|
|
terra: 5,
|
|
aptos: 1,
|
|
oasis: 1,
|
|
moonbeam: 2,
|
|
},
|
|
}
|
|
}
|