diff --git a/.env.sample b/.env.sample index 11c8a26..2706f6f 100644 --- a/.env.sample +++ b/.env.sample @@ -2,4 +2,6 @@ POKT_RPC_FULL_HOST= HTTP_SERVER_PORT=8080 POKT_RPC_TIMEOUT=5s ENVIRONMENT_STAGE=development -APPSTAKE_PRIVATE_KEYS= \ No newline at end of file +POKT_APPLICATIONS_ENCRYPTION_KEY= +SESSION_CACHE_TTL=75m +DB_CONNECTION_URL=postgres://postgres:mypassword@localhost:5432/postgres?sslmode=disable \ No newline at end of file diff --git a/README.md b/README.md index acfab7c..1232ca3 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,23 @@ Learn more about the vision and overall architecture [overview](docs%2Foverview. ``` 3. Run the binary `./main` +## Creating a DB Migration +Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. +Before running a migration make sure to install the go lang migration cli on your machine. +https://github.com/golang-migrate/migrate/tree/master/cmd/migrate +```sh +./scripts/migration.sh -n {migration_name} +``` +This command will generate a up and down migration in `db_migrations` + +## Applying a DB Migration +DB Migrations are applied upon server start, but as well, it can be applied manually through: +```sh +./scripts/migration.sh {--down or --up} {number_of_times} +./scripts/migration.sh -d 1 +./scripts/migration.sh -u 1 +``` + ## Running Tests Before running any tests make sure to have the mock files in placed at `./mocks` folder. You can generate the mock files through: diff --git a/cmd/gateway_server/internal/config/dot_env_config_provider.go b/cmd/gateway_server/internal/config/dot_env_config_provider.go index cf8fcf0..1d1fde7 100644 --- a/cmd/gateway_server/internal/config/dot_env_config_provider.go +++ b/cmd/gateway_server/internal/config/dot_env_config_provider.go @@ -4,44 +4,50 @@ import ( "fmt" "github.com/joho/godotenv" "os" - "os-gateway/internal/config" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/internal/config" "strconv" - "strings" "time" ) // Environment variable names const ( - poktRPCFullHostEnv = "POKT_RPC_FULL_HOST" - httpServerPortEnv = "HTTP_SERVER_PORT" - poktRPCTimeoutEnv = "POKT_RPC_TIMEOUT" - environmentStageEnv = "ENVIRONMENT_STAGE" - // TODO: Use an encrypted key file or move over to a encrypted DB. (@Blade) - appStakesPrivateKeyEnv = "APPSTAKE_PRIVATE_KEYS" + poktRPCFullHostEnv = "POKT_RPC_FULL_HOST" + httpServerPortEnv = "HTTP_SERVER_PORT" + poktRPCTimeoutEnv = "POKT_RPC_TIMEOUT" + dbConnectionUrlEnv = "DB_CONNECTION_URL" + sessionCacheTTLEnv = "SESSION_CACHE_TTL" + environmentStageEnv = "ENVIRONMENT_STAGE" + poktApplicationsEncryptionKeyEnv = "POKT_APPLICATIONS_ENCRYPTION_KEY" ) // DotEnvConfigProvider implements the GatewayServerProvider interface. type DotEnvConfigProvider struct { - poktRPCFullHost string - httpServerPort uint - poktRPCTimeout time.Duration - environmentStage config.EnvironmentStage - appStakes []*models.Ed25519Account + poktRPCFullHost string + httpServerPort uint + poktRPCTimeout time.Duration + sessionCacheTTL time.Duration + environmentStage config.EnvironmentStage + poktApplicationsEncryptionKey string + databaseConnectionUrl string } // GetPoktRPCFullHost returns the PoktRPCFullHost value. -func (c *DotEnvConfigProvider) GetPoktRPCFullHost() string { +func (c DotEnvConfigProvider) GetPoktRPCFullHost() string { return c.poktRPCFullHost } // GetHTTPServerPort returns the HTTPServerPort value. -func (c *DotEnvConfigProvider) GetHTTPServerPort() uint { +func (c DotEnvConfigProvider) GetHTTPServerPort() uint { return c.httpServerPort } // GetPoktRPCTimeout returns the PoktRPCTimeout value. -func (c *DotEnvConfigProvider) GetPoktRPCTimeout() time.Duration { +func (c DotEnvConfigProvider) GetPoktRPCTimeout() time.Duration { + return c.poktRPCTimeout +} + +// GetSessionCacheTTL returns the time value for session to expire in cache. +func (c DotEnvConfigProvider) GetSessionCacheTTL() time.Duration { return c.poktRPCTimeout } @@ -50,9 +56,14 @@ func (c DotEnvConfigProvider) GetEnvironmentStage() config.EnvironmentStage { return c.environmentStage } -// GetAppStakes returns the app stakes for sending a relay -func (c *DotEnvConfigProvider) GetAppStakes() []*models.Ed25519Account { - return c.appStakes +// GetPoktApplicationsEncryptionKey: Key used to decrypt pokt applications private key. +func (c DotEnvConfigProvider) GetPoktApplicationsEncryptionKey() string { + return c.poktApplicationsEncryptionKey +} + +// GetDatabaseConnectionUrl returns the PoktRPCFullHost value. +func (c DotEnvConfigProvider) GetDatabaseConnectionUrl() string { + return c.databaseConnectionUrl } // NewDotEnvConfigProvider creates a new instance of DotEnvConfigProvider. @@ -62,71 +73,37 @@ func NewDotEnvConfigProvider() *DotEnvConfigProvider { panic(fmt.Sprintf("Error loading .env file: %s", err)) } - poktRPCFullHost, err := getEnvVar(poktRPCFullHostEnv) - if err != nil { - panic(fmt.Sprintf("Error getting %s: %s", poktRPCFullHostEnv, err)) - } - - httpServerPortStr, err := getEnvVar(httpServerPortEnv) - if err != nil { - panic(fmt.Sprintf("Error getting %s: %s", httpServerPortEnv, err)) - } - - poktRPCTimeoutStr, err := getEnvVar(poktRPCTimeoutEnv) - if err != nil { - panic(fmt.Sprintf("Error getting %s: %s", poktRPCTimeoutEnv, err)) - } - - environmentStage, err := getEnvVar(environmentStageEnv) + poktRPCTimeout, err := time.ParseDuration(getEnvVar(poktRPCTimeoutEnv)) if err != nil { - panic(fmt.Sprintf("Error getting %s: %s", environmentStageEnv, err)) + panic(fmt.Sprintf("Error parsing %s: %s", poktRPCTimeoutEnv, err)) } - httpServerPort, err := strconv.ParseUint(httpServerPortStr, 10, 64) + httpServerPort, err := strconv.ParseUint(getEnvVar(httpServerPortEnv), 10, 64) if err != nil { panic(fmt.Sprintf("Error parsing %s: %s", httpServerPortEnv, err)) } - poktRPCTimeout, err := time.ParseDuration(poktRPCTimeoutStr) + sessionCacheTTLDuration, err := time.ParseDuration(getEnvVar(sessionCacheTTLEnv)) if err != nil { - panic(fmt.Sprintf("Error parsing %s: %s", poktRPCTimeoutEnv, err)) + panic(fmt.Sprintf("Error parsing %s: %s", sessionCacheTTLDuration, err)) } return &DotEnvConfigProvider{ - poktRPCFullHost: poktRPCFullHost, - httpServerPort: uint(httpServerPort), - poktRPCTimeout: poktRPCTimeout, - environmentStage: config.EnvironmentStage(environmentStage), - appStakes: getAppStakesFromEnv(), + poktRPCFullHost: getEnvVar(poktRPCFullHostEnv), + httpServerPort: uint(httpServerPort), + poktRPCTimeout: poktRPCTimeout, + sessionCacheTTL: sessionCacheTTLDuration, + databaseConnectionUrl: getEnvVar(dbConnectionUrlEnv), + environmentStage: config.EnvironmentStage(getEnvVar(environmentStageEnv)), + poktApplicationsEncryptionKey: getEnvVar(poktApplicationsEncryptionKeyEnv), } } // getEnvVar retrieves the value of the environment variable with error handling. -func getEnvVar(name string) (string, error) { +func getEnvVar(name string) string { value, exists := os.LookupEnv(name) if !exists { - return "", fmt.Errorf("%s not set", name) - } - return value, nil -} - -func getAppStakesFromEnv() []*models.Ed25519Account { - privateKeys, err := getEnvVar(appStakesPrivateKeyEnv) - if err != nil { - panic(fmt.Sprintf("Error parsing %s", appStakesPrivateKeyEnv)) - } - var appStakePrivateKeys []*models.Ed25519Account - for _, key := range strings.Split(privateKeys, ",") { - appStake, err := models.NewAccount(key) - if err != nil { - panic("Failed to parse appstake key") - } - appStakePrivateKeys = append(appStakePrivateKeys, appStake) + panic(fmt.Errorf("%s not set", name)) } - - if len(appStakePrivateKeys) == 0 { - panic("app stakes were not provided or unable to parse successfully") - } - - return appStakePrivateKeys + return value } diff --git a/cmd/gateway_server/internal/config/provider.go b/cmd/gateway_server/internal/config/provider.go index ca717ca..9ab763f 100644 --- a/cmd/gateway_server/internal/config/provider.go +++ b/cmd/gateway_server/internal/config/provider.go @@ -1,15 +1,13 @@ package config import ( - "os-gateway/internal/config" - "os-gateway/pkg/pokt/pokt_v0/models" - "time" + "pokt_gateway_server/internal/config" ) type GatewayServerProvider interface { - GetPoktRPCFullHost() string GetHTTPServerPort() uint - GetPoktRPCTimeout() time.Duration - GetAppStakes() []*models.Ed25519Account + config.DBCredentialsProvider + config.PoktNodeConfigProvider + config.SecretProvider config.EnvironmentProvider } diff --git a/cmd/gateway_server/internal/controllers/pokt_apps.go b/cmd/gateway_server/internal/controllers/pokt_apps.go new file mode 100644 index 0000000..029f9f8 --- /dev/null +++ b/cmd/gateway_server/internal/controllers/pokt_apps.go @@ -0,0 +1,44 @@ +package controllers + +import ( + "github.com/pquerna/ffjson/ffjson" + "github.com/valyala/fasthttp" + "go.uber.org/zap" + "pokt_gateway_server/cmd/gateway_server/internal/models" + "pokt_gateway_server/cmd/gateway_server/internal/transform" + "pokt_gateway_server/internal/pokt_applications_registry" + "pokt_gateway_server/pkg/pokt/pokt_v0" +) + +// RelayController handles relay requests for a specific chain. +type PoktAppsController struct { + logger *zap.Logger + poktClient pokt_v0.PocketService + appRegistry pokt_applications_registry.Service +} + +// NewRelayController creates a new instance of RelayController. +func NewPoktAppsController(appRegistry pokt_applications_registry.Service, logger *zap.Logger) *PoktAppsController { + return &PoktAppsController{appRegistry: appRegistry, logger: logger} +} + +// GetAllPoktApps is the path for relay requests. +const GetAllPoktApps = "/poktapps" + +// HandleRelay handles incoming relay requests. +func (c *PoktAppsController) GetAll(ctx *fasthttp.RequestCtx) { + applications := c.appRegistry.GetApplications() + appsPublic := []*models.PoktApplication{} + for _, app := range applications { + appsPublic = append(appsPublic, transform.ToPoktApplication(app)) + } + result, err := ffjson.Marshal(appsPublic) + if err != nil { + ctx.Response.SetStatusCode(fasthttp.StatusInternalServerError) + return + } + // Send a successful response back to the client. + ctx.Response.SetStatusCode(fasthttp.StatusOK) + ctx.Response.Header.Set("Content-Type", "application/json") + ctx.Response.SetBody(result) +} diff --git a/cmd/gateway_server/internal/controllers/relay.go b/cmd/gateway_server/internal/controllers/relay.go index 9bd92c5..85d906b 100644 --- a/cmd/gateway_server/internal/controllers/relay.go +++ b/cmd/gateway_server/internal/controllers/relay.go @@ -2,12 +2,14 @@ package controllers import ( "errors" + "fmt" "github.com/valyala/fasthttp" "go.uber.org/zap" - "os-gateway/cmd/gateway_server/internal/common" - slice_common "os-gateway/pkg/common" - "os-gateway/pkg/pokt/pokt_v0" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/cmd/gateway_server/internal/common" + "pokt_gateway_server/internal/pokt_applications_registry" + slice_common "pokt_gateway_server/pkg/common" + "pokt_gateway_server/pkg/pokt/pokt_v0" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "strings" "sync" ) @@ -16,14 +18,14 @@ var ErrRelayChannelClosed = errors.New("concurrent relay channel closed") // RelayController handles relay requests for a specific chain. type RelayController struct { - logger *zap.Logger - poktClient pokt_v0.PocketService - appStakes []*models.Ed25519Account + logger *zap.Logger + poktClient pokt_v0.PocketService + appRegistry pokt_applications_registry.Service } // NewRelayController creates a new instance of RelayController. -func NewRelayController(poktClient pokt_v0.PocketService, appStakes []*models.Ed25519Account, logger *zap.Logger) *RelayController { - return &RelayController{poktClient: poktClient, appStakes: appStakes, logger: logger} +func NewRelayController(poktClient pokt_v0.PocketService, appRegistry pokt_applications_registry.Service, logger *zap.Logger) *RelayController { + return &RelayController{poktClient: poktClient, appRegistry: appRegistry, logger: logger} } // RelayHandlerPath is the path for relay requests. @@ -43,15 +45,22 @@ func (c *RelayController) HandleRelay(ctx *fasthttp.RequestCtx) { return } + applications, ok := c.appRegistry.GetApplicationsByChainId(chainID) + + if !ok { + common.JSONError(ctx, fmt.Sprintf("%s chainId not supported with existing application registry", chainID), fasthttp.StatusBadRequest) + return + } + // Get a random app stake from the available list. - appStake := slice_common.GetRandomElement(c.appStakes) + appStake := slice_common.GetRandomElement(applications) if appStake == nil { common.JSONError(ctx, "App stake not provided", fasthttp.StatusInternalServerError) return } sessionResp, err := c.poktClient.GetSession(&models.GetSessionRequest{ - AppPubKey: appStake.PublicKey, + AppPubKey: appStake.Ed25519Account.PublicKey, Chain: chainID, }) @@ -67,7 +76,7 @@ func (c *RelayController) HandleRelay(ctx *fasthttp.RequestCtx) { Method: string(ctx.Method()), Path: path, }, - Signer: appStake, + Signer: appStake.Ed25519Account, Chain: chainID, } diff --git a/cmd/gateway_server/internal/controllers/relay_test.go b/cmd/gateway_server/internal/controllers/relay_test.go index 0ed24a6..698dc75 100644 --- a/cmd/gateway_server/internal/controllers/relay_test.go +++ b/cmd/gateway_server/internal/controllers/relay_test.go @@ -3,8 +3,8 @@ package controllers // Basic imports import ( "errors" - "os-gateway/mocks" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/mocks" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "testing" "github.com/stretchr/testify/suite" diff --git a/cmd/gateway_server/internal/models/pokt_application.go b/cmd/gateway_server/internal/models/pokt_application.go new file mode 100644 index 0000000..baaca5d --- /dev/null +++ b/cmd/gateway_server/internal/models/pokt_application.go @@ -0,0 +1,8 @@ +package models + +type PoktApplication struct { + ID string `json:"id"` + MaxRelays int `json:"max_relays"` + Chains []string `json:"chain"` + Address string `json:"address"` +} diff --git a/cmd/gateway_server/internal/transform/pokt_application.go b/cmd/gateway_server/internal/transform/pokt_application.go new file mode 100644 index 0000000..4a576a8 --- /dev/null +++ b/cmd/gateway_server/internal/transform/pokt_application.go @@ -0,0 +1,15 @@ +package transform + +import ( + "pokt_gateway_server/cmd/gateway_server/internal/models" + internal_model "pokt_gateway_server/internal/pokt_applications_registry/models" +) + +func ToPoktApplication(signer *internal_model.PoktApplicationSigner) *models.PoktApplication { + return &models.PoktApplication{ + ID: signer.ID, + MaxRelays: int(signer.MaxRelays), + Chains: signer.Chains, + Address: signer.PoktApplication.Address, + } +} diff --git a/cmd/gateway_server/main.go b/cmd/gateway_server/main.go index 5c21d8b..0ac40eb 100644 --- a/cmd/gateway_server/main.go +++ b/cmd/gateway_server/main.go @@ -1,20 +1,28 @@ package main import ( + "context" + "database/sql" "fmt" - fasthttpprometheus "github.com/flf2ko/fasthttp-prometheus" - "log" - "os-gateway/cmd/gateway_server/internal/config" - "os-gateway/cmd/gateway_server/internal/controllers" - "os-gateway/internal/logging" - "os-gateway/internal/pokt_client_decorators" - "os-gateway/pkg/pokt/pokt_v0" - "os-gateway/pkg/pokt/pokt_v0/models" - "time" - "github.com/fasthttp/router" + fasthttpprometheus "github.com/flf2ko/fasthttp-prometheus" + "github.com/golang-migrate/migrate/v4" + "github.com/golang-migrate/migrate/v4/database/postgres" + "github.com/golang-migrate/migrate/v4/source/iofs" + "github.com/jackc/pgx/v4/pgxpool" "github.com/jellydator/ttlcache/v3" + "github.com/pkg/errors" "github.com/valyala/fasthttp" + "go.uber.org/zap" + root "pokt_gateway_server" + "pokt_gateway_server/cmd/gateway_server/internal/config" + "pokt_gateway_server/cmd/gateway_server/internal/controllers" + "pokt_gateway_server/internal/db_query" + "pokt_gateway_server/internal/logging" + "pokt_gateway_server/internal/pokt_applications_registry" + "pokt_gateway_server/internal/pokt_client_decorators" + "pokt_gateway_server/pkg/pokt/pokt_v0" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" ) func main() { @@ -28,6 +36,15 @@ func main() { panic(err) } + querier, pool, err := initDB(logger, gatewayConfigProvider) + if err != nil { + logger.Sugar().Fatal(err) + return + } + + // Close connection to pool afterward + defer pool.Close() + // Initialize a POKT client using the configured POKT RPC host and timeout client, err := pokt_v0.NewBasicClient(gatewayConfigProvider.GetPoktRPCFullHost(), gatewayConfigProvider.GetPoktRPCTimeout()) if err != nil { @@ -38,11 +55,13 @@ func main() { // Initialize a TTL cache for session caching sessionCache := ttlcache.New[string, *models.GetSessionResponse]( - ttlcache.WithTTL[string, *models.GetSessionResponse](time.Minute * 75), //@todo: make this configurable via env ? + ttlcache.WithTTL[string, *models.GetSessionResponse](gatewayConfigProvider.GetSessionCacheTTL()), //@todo: make this configurable via env ? ) - // Create a relay controller with a cached POKT client and the loggeri - relayController := controllers.NewRelayController(pokt_client_decorators.NewCachedClient(client, sessionCache), gatewayConfigProvider.GetAppStakes(), logger) + poktApplicationRegistry := pokt_applications_registry.NewCachedRegistry(client, querier, gatewayConfigProvider, logger.Named("pokt_application_registry")) + + // Create a relay controller with the necessary dependencies (logger, registry, cached relayer) + relayController := controllers.NewRelayController(pokt_client_decorators.NewCachedClient(client, sessionCache), poktApplicationRegistry, logger) // Define routers r := router.New() @@ -56,6 +75,57 @@ func main() { // Start the fasthttp server and listen on the configured server port if err := fasthttp.ListenAndServe(fmt.Sprintf(":%d", gatewayConfigProvider.GetHTTPServerPort()), fastpHandler); err != nil { // If an error occurs during server startup, log the error and exit - log.Fatalf("Error in ListenAndServe: %s", err) + logger.Sugar().Fatalw("Error in ListenAndServe", "err", err) } } + +func initDB(logger *zap.Logger, config config.GatewayServerProvider) (db_query.Querier, *pgxpool.Pool, error) { + + // initialize database + sqldb, err := sql.Open("postgres", config.GetDatabaseConnectionUrl()) + if err != nil { + return nil, nil, errors.WithMessage(err, "failed to init db") + } + + postgresDriver, err := postgres.WithInstance(sqldb, &postgres.Config{}) + if err != nil { + return nil, nil, errors.WithMessage(err, "failed to init postgres driver") + } + + source, err := iofs.New(root.Migrations, "db_migrations") + + if err != nil { + return nil, nil, errors.WithMessage(err, "failed to create migration fs") + } + + // Automatic Migrations + m, err := migrate.NewWithInstance("iofs", source, "postgres", postgresDriver) + + if err != nil { + return nil, nil, errors.WithMessage(err, "failed to migrate") + } + + err = m.Up() + if err != nil && err != migrate.ErrNoChange { + logger.Sugar().Warn("Migration warning", "err", err) + return nil, nil, err + } + + // DB only needs to be open for migration + err = postgresDriver.Close() + if err != nil { + return nil, nil, err + } + err = sqldb.Close() + if err != nil { + return nil, nil, err + } + + // open up connection pool for actual sql queries + pool, err := pgxpool.Connect(context.Background(), config.GetDatabaseConnectionUrl()) + if err != nil { + return nil, pool, err + } + return db_query.NewQuerier(pool), nil, nil + +} diff --git a/db_migrations/000001_initial.down.sql b/db_migrations/000001_initial.down.sql new file mode 100644 index 0000000..e69de29 diff --git a/db_migrations/000001_initial.up.sql b/db_migrations/000001_initial.up.sql new file mode 100644 index 0000000..5d9c97d --- /dev/null +++ b/db_migrations/000001_initial.up.sql @@ -0,0 +1,18 @@ +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS pgcrypto; + +CREATE TABLE base_model +( + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP, + deleted_at TIMESTAMP +); + +CREATE TABLE pokt_applications +( + id UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), + encrypted_private_key BYTEA NOT NULL +) INHERITS (base_model); + + + diff --git a/docker-compose.yml b/docker-compose.yml index e231877..453855b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,4 +8,18 @@ services: ports: - "${HTTP_SERVER_PORT}:${HTTP_SERVER_PORT}" env_file: - - ./.env \ No newline at end of file + - ./.env + + postgres: + image: postgres:latest + environment: + POSTGRES_DB: mydatabase + POSTGRES_USER: myuser + POSTGRES_PASSWORD: mypassword + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + +volumes: + postgres_data: \ No newline at end of file diff --git a/docs/api-endpoints.md b/docs/api-endpoints.md index 1c74df3..16ca3f1 100644 --- a/docs/api-endpoints.md +++ b/docs/api-endpoints.md @@ -4,12 +4,11 @@ The Gateway Server currently exposes all its API endpoints in form of HTTP endpo `x-api-key` is an api key set by the gateway operator to transmit internal private data -| Endpoint | HTTP METHOD | Description | HEADERS | Request Parameters | -|-----------------------------|-------------|-----------------------------------------------------------------------|-------------|---------------------------------------------------------------------| -| `/relay/{chain_id}` | ANY | The main endpoint for your reverse proxy to send requests too | ANY | `{chain_id}` - Network identifier | -| `/metrics` | GET | Metadata on the gateway server performance for observability purposes | N/A | N/A | -| `/poktapp` | POST | Adds an existing app stake to the appstake database | `x-api-key` | `encrypted_private_key` - private key of app stake that's encrypted | -| `/poktapp` | DELETE | REmoves an existing app stake from the appstake database | `x-api-key` | `address` - address of the appstake that's encrypted | -| `/poktapp` | GET | A list of all the avaliable app stakes | `x-api-key` | N/A | -| `/poktapp/{app_id}` | GET | Return a specific app stake | `x-api-key` | `app_id` - internal app id | -| `/appstakes/{app_id}/chains` | POST | Edits the app stake chains | `x-api-key` | `chain_ids` - an string array of chain ids | +| Endpoint | HTTP METHOD | Description | HEADERS | Request Parameters | +|----------------------------|-------------|-----------------------------------------------------------------------|-------------|---------------------------------------------------------------------| +| `/relay/{chain_id}` | ANY | The main endpoint for your reverse proxy to send requests too | ANY | `{chain_id}` - Network identifier | +| `/metrics` | GET | Metadata on the gateway server performance for observability purposes | N/A | N/A | +| `/poktapp` | POST | Adds an existing app stake to the appstake database | `x-api-key` | `encrypted_private_key` - private key of app stake that's encrypted | +| `/poktapp` | DELETE | Removes an existing app stake from the appstake database | `x-api-key` | `address` - address of the appstake that's encrypted | +| `/poktapp` | GET | A list of all the avaliable app stakes | `x-api-key` | N/A | +| `/poktapp/{app_id}/chains` | POST | Edits the app stake chains | `x-api-key` | `chain_ids` - an string array of chain ids | diff --git a/go.mod b/go.mod index 56d959e..2ff7efd 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,23 @@ -module os-gateway +module pokt_gateway_server go 1.21.4 require ( github.com/fasthttp/router v1.4.22 + github.com/flf2ko/fasthttp-prometheus v0.1.0 + github.com/golang-migrate/migrate/v4 v4.17.0 + github.com/jackc/pgconn v1.14.0 + github.com/jackc/pgtype v1.14.0 + github.com/jackc/pgx/v4 v4.18.1 github.com/jellydator/ttlcache/v3 v3.1.0 github.com/joho/godotenv v1.5.1 github.com/pkg/errors v0.9.1 github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 + github.com/prometheus/client_golang v1.15.0 github.com/stretchr/testify v1.8.4 github.com/valyala/fasthttp v1.51.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.15.0 + golang.org/x/crypto v0.17.0 ) require ( @@ -19,21 +25,31 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/flf2ko/fasthttp-prometheus v0.1.0 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/puddle v1.3.0 // indirect github.com/klauspost/compress v1.17.3 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.15.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/stretchr/objx v0.5.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect + go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.14.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 28662f5..c1af40d 100644 --- a/go.sum +++ b/go.sum @@ -1,30 +1,148 @@ +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dhui/dktest v0.4.0 h1:z05UmuXZHO/bgj/ds2bGMBu8FI4WA+Ag/m3ghL+om7M= +github.com/dhui/dktest v0.4.0/go.mod h1:v/Dbz1LgCBOi2Uki2nUqLBGa83hWBGFMu5MrgMDCc78= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/fasthttp/router v1.4.22 h1:qwWcYBbndVDwts4dKaz+A2ehsnbKilmiP6pUhXBfYKo= github.com/fasthttp/router v1.4.22/go.mod h1:KeMvHLqhlB9vyDWD5TSvTccl9qeWrjSSiTJrJALHKV0= github.com/flf2ko/fasthttp-prometheus v0.1.0 h1:hj4K3TwJ2B7Fe2E7lWE/eb9mtb7gBvwURXr4+iEFoCI= github.com/flf2ko/fasthttp-prometheus v0.1.0/go.mod h1:5tGRWsJeP8ABLYovqPxa5c/zCgnsYUhhC1ivs/Kv/c4= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU= +github.com/golang-migrate/migrate/v4 v4.17.0/go.mod h1:+Cp2mtLP4/aXDTKb9wmXYitdrNx2HGs45rbWAo6OsKM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q= +github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= +github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= +github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA= github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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= @@ -39,15 +157,35 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -55,26 +193,120 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/internal/config/config_provider.go b/internal/config/config_provider.go index 471e7c3..03aa7eb 100644 --- a/internal/config/config_provider.go +++ b/internal/config/config_provider.go @@ -1,11 +1,26 @@ package config +import "time" + type EnvironmentStage string const ( StageProduction EnvironmentStage = "production" ) +type SecretProvider interface { + GetPoktApplicationsEncryptionKey() string +} + +type DBCredentialsProvider interface { + GetDatabaseConnectionUrl() string +} + type EnvironmentProvider interface { GetEnvironmentStage() EnvironmentStage } + +type PoktNodeConfigProvider interface { + GetPoktRPCFullHost() string + GetPoktRPCTimeout() time.Duration +} diff --git a/internal/db_query/queries.sql b/internal/db_query/queries.sql new file mode 100644 index 0000000..4938bf8 --- /dev/null +++ b/internal/db_query/queries.sql @@ -0,0 +1,7 @@ +-- name: GetPoktApplications :many +SELECT id, pgp_sym_decrypt(encrypted_private_key, pggen.arg('encryption_key')) AS decrypted_private_key +FROM pokt_applications; + +-- name: InsertPoktApplications :exec +INSERT INTO pokt_applications (encrypted_private_key) +VALUES (pgp_sym_encrypt(pggen.arg('private_key'), pggen.arg('encryption_key'))); \ No newline at end of file diff --git a/internal/db_query/queries.sql.go b/internal/db_query/queries.sql.go new file mode 100644 index 0000000..2bf2769 --- /dev/null +++ b/internal/db_query/queries.sql.go @@ -0,0 +1,133 @@ +// Code generated by pggen. DO NOT EDIT. + +package db_query + +import ( + "context" + "fmt" + "github.com/jackc/pgconn" + "github.com/jackc/pgtype" + "github.com/jackc/pgx/v4" +) + +// Querier is a typesafe Go interface backed by SQL queries. +type Querier interface { + GetPoktApplications(ctx context.Context, encryptionKey string) ([]GetPoktApplicationsRow, error) + InsertPoktApplications(ctx context.Context, privateKey string, encryptionKey string) (pgconn.CommandTag, error) +} + +var _ Querier = &DBQuerier{} + +type DBQuerier struct { + conn genericConn // underlying Postgres transport to use + types *typeResolver // resolve types by name +} + +// genericConn is a connection like *pgx.Conn, pgx.Tx, or *pgxpool.Pool. +type genericConn interface { + Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) + QueryRow(ctx context.Context, sql string, args ...any) pgx.Row + Exec(ctx context.Context, sql string, arguments ...any) (pgconn.CommandTag, error) +} + +// NewQuerier creates a DBQuerier that implements Querier. +func NewQuerier(conn genericConn) *DBQuerier { + return &DBQuerier{conn: conn, types: newTypeResolver()} +} + +// typeResolver looks up the pgtype.ValueTranscoder by Postgres type name. +type typeResolver struct { + connInfo *pgtype.ConnInfo // types by Postgres type name +} + +func newTypeResolver() *typeResolver { + ci := pgtype.NewConnInfo() + return &typeResolver{connInfo: ci} +} + +// findValue find the OID, and pgtype.ValueTranscoder for a Postgres type name. +func (tr *typeResolver) findValue(name string) (uint32, pgtype.ValueTranscoder, bool) { + typ, ok := tr.connInfo.DataTypeForName(name) + if !ok { + return 0, nil, false + } + v := pgtype.NewValue(typ.Value) + return typ.OID, v.(pgtype.ValueTranscoder), true +} + +// setValue sets the value of a ValueTranscoder to a value that should always +// work and panics if it fails. +func (tr *typeResolver) setValue(vt pgtype.ValueTranscoder, val interface{}) pgtype.ValueTranscoder { + if err := vt.Set(val); err != nil { + panic(fmt.Sprintf("set ValueTranscoder %T to %+v: %s", vt, val, err)) + } + return vt +} + +const getPoktApplicationsSQL = `SELECT id, pgp_sym_decrypt(encrypted_private_key, $1) AS decrypted_private_key +FROM pokt_applications;` + +type GetPoktApplicationsRow struct { + ID pgtype.UUID `json:"id"` + DecryptedPrivateKey string `json:"decrypted_private_key"` +} + +// GetPoktApplications implements Querier.GetPoktApplications. +func (q *DBQuerier) GetPoktApplications(ctx context.Context, encryptionKey string) ([]GetPoktApplicationsRow, error) { + ctx = context.WithValue(ctx, "pggen_query_name", "GetPoktApplications") + rows, err := q.conn.Query(ctx, getPoktApplicationsSQL, encryptionKey) + if err != nil { + return nil, fmt.Errorf("query GetPoktApplications: %w", err) + } + defer rows.Close() + items := []GetPoktApplicationsRow{} + for rows.Next() { + var item GetPoktApplicationsRow + if err := rows.Scan(&item.ID, &item.DecryptedPrivateKey); err != nil { + return nil, fmt.Errorf("scan GetPoktApplications row: %w", err) + } + items = append(items, item) + } + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("close GetPoktApplications rows: %w", err) + } + return items, err +} + +const insertPoktApplicationsSQL = `INSERT INTO pokt_applications (encrypted_private_key) +VALUES (pgp_sym_encrypt($1, $2));` + +// InsertPoktApplications implements Querier.InsertPoktApplications. +func (q *DBQuerier) InsertPoktApplications(ctx context.Context, privateKey string, encryptionKey string) (pgconn.CommandTag, error) { + ctx = context.WithValue(ctx, "pggen_query_name", "InsertPoktApplications") + cmdTag, err := q.conn.Exec(ctx, insertPoktApplicationsSQL, privateKey, encryptionKey) + if err != nil { + return cmdTag, fmt.Errorf("exec query InsertPoktApplications: %w", err) + } + return cmdTag, err +} + +// textPreferrer wraps a pgtype.ValueTranscoder and sets the preferred encoding +// format to text instead binary (the default). pggen uses the text format +// when the OID is unknownOID because the binary format requires the OID. +// Typically occurs for unregistered types. +type textPreferrer struct { + pgtype.ValueTranscoder + typeName string +} + +// PreferredParamFormat implements pgtype.ParamFormatPreferrer. +func (t textPreferrer) PreferredParamFormat() int16 { return pgtype.TextFormatCode } + +func (t textPreferrer) NewTypeValue() pgtype.Value { + return textPreferrer{ValueTranscoder: pgtype.NewValue(t.ValueTranscoder).(pgtype.ValueTranscoder), typeName: t.typeName} +} + +func (t textPreferrer) TypeName() string { + return t.typeName +} + +// unknownOID means we don't know the OID for a type. This is okay for decoding +// because pgx call DecodeText or DecodeBinary without requiring the OID. For +// encoding parameters, pggen uses textPreferrer if the OID is unknown. +const unknownOID = 0 diff --git a/internal/logging/logger.go b/internal/logging/logger.go index 589bd21..06f457a 100644 --- a/internal/logging/logger.go +++ b/internal/logging/logger.go @@ -2,7 +2,7 @@ package logging import ( "go.uber.org/zap" - "os-gateway/internal/config" + "pokt_gateway_server/internal/config" ) func NewLogger(provider config.EnvironmentProvider) (*zap.Logger, error) { diff --git a/internal/pokt_applications_registry/models/application.go b/internal/pokt_applications_registry/models/application.go new file mode 100644 index 0000000..d770573 --- /dev/null +++ b/internal/pokt_applications_registry/models/application.go @@ -0,0 +1,13 @@ +package models + +import "pokt_gateway_server/pkg/pokt/pokt_v0/models" + +type PoktApplicationSigner struct { + ID string `json:"id"` + *models.Ed25519Account + *models.PoktApplication +} + +func NewPoktApplicationSigner(account *models.Ed25519Account, application *models.PoktApplication) *PoktApplicationSigner { + return &PoktApplicationSigner{Ed25519Account: account, PoktApplication: application} +} diff --git a/internal/pokt_applications_registry/registry_service.go b/internal/pokt_applications_registry/registry_service.go new file mode 100644 index 0000000..454d018 --- /dev/null +++ b/internal/pokt_applications_registry/registry_service.go @@ -0,0 +1,170 @@ +package pokt_applications_registry + +import ( + "context" + "go.uber.org/zap" + "pokt_gateway_server/internal/config" + "pokt_gateway_server/internal/db_query" + "pokt_gateway_server/internal/pokt_applications_registry/models" + "pokt_gateway_server/pkg/pokt/pokt_v0" + pokt "pokt_gateway_server/pkg/pokt/pokt_v0/models" + "sort" + "strings" + "sync" + "time" +) + +const ( + applicationUpdateInterval = time.Second * 15 +) + +// CachedRegistry is a caching layer for storing and retrieving from internal DB and POKT's blockchain state +type CachedRegistry struct { + pocketClient pokt_v0.PocketService + dbQuery db_query.Querier + logger *zap.Logger + secretProvider config.SecretProvider + applications []*models.PoktApplicationSigner + applicationChainMap map[string][]*models.PoktApplicationSigner + lockCache sync.RWMutex +} + +// NewCachedRegistry creates a new instance of CachedRegistry. +func NewCachedRegistry(pocketClient pokt_v0.PocketService, dbQuery db_query.Querier, secretProvider config.SecretProvider, logger *zap.Logger) *CachedRegistry { + cachedRegistry := CachedRegistry{pocketClient: pocketClient, dbQuery: dbQuery, logger: logger, secretProvider: secretProvider} + err := cachedRegistry.updateApplicationCache() + if err != nil { + cachedRegistry.logger.Sugar().Warnw("failed to retrieve applications on init", "err", err) + } + cachedRegistry.startCacheUpdater() + return &cachedRegistry +} + +// GetApplications returns all the cached Pocket applications. +func (c *CachedRegistry) GetApplications() []*models.PoktApplicationSigner { + c.lockCache.RLock() + defer c.lockCache.RUnlock() + return c.applications +} + +// GetApplicationsByChainId returns Pocket applications filtered by a specific chain ID. +func (c *CachedRegistry) GetApplicationsByChainId(chainId string) ([]*models.PoktApplicationSigner, bool) { + c.lockCache.RLock() + defer c.lockCache.RUnlock() + app, ok := c.applicationChainMap[chainId] + return app, ok +} + +// updateApplicationCache refreshes the cache with the latest Pocket applications and their associated information. +func (c *CachedRegistry) updateApplicationCache() error { + // Retrieve Pocket applications from the database + storedAppsPK, err := c.dbQuery.GetPoktApplications(context.Background(), c.secretProvider.GetPoktApplicationsEncryptionKey()) + if err != nil { + return err + } + + // Convert the encrypted private keys to Pocket Ed25519 accounts + storedApps := []*pokt.Ed25519Account{} + for _, app := range storedAppsPK { + account, err := pokt.NewAccount(app.DecryptedPrivateKey) + if err != nil { + // Log a warning if there is an error converting the private key + c.logger.Sugar().Warnw("failed to update application", "err", err, "app", app.ID) + continue + } + storedApps = append(storedApps, account) + } + + // Retrieve the latest staked applications from the Pocket service + networkStakedApps, err := c.pocketClient.GetLatestStakedApplications() + if err != nil { + return err + } + + // Create a list of PoktApplicationSigner by combining Pocket accounts and staked applications + poktApplicationSigners := []*models.PoktApplicationSigner{} + for _, networkApp := range networkStakedApps { + for _, storedAccount := range storedApps { + // Check if the account address matches, and create a PoktApplicationSigner if there's a match + if strings.EqualFold(networkApp.Address, storedAccount.Address) { + poktApplicationSigners = append(poktApplicationSigners, models.NewPoktApplicationSigner(storedAccount, networkApp)) + } + } + } + + // Create a map to organize PoktApplicationSigners by chain ID + applicationChainMap := make(map[string][]*models.PoktApplicationSigner) + + // Iterate through each PoktApplicationSigner and associate it with the corresponding chain IDs + for _, signer := range poktApplicationSigners { + for _, chainID := range signer.PoktApplication.Chains { + // If the chain ID is not in the map, create a new entry + if _, ok := applicationChainMap[chainID]; !ok { + applicationChainMap[chainID] = make([]*models.PoktApplicationSigner, 0) + } + // Append the PoktApplicationSigner to the chain ID entry in the map + applicationChainMap[chainID] = append(applicationChainMap[chainID], signer) + } + } + + // No changes needed so will not replace. We do this to also prevent regenerating AAT's + if arePoktApplicationSignersEqual(c.applications, poktApplicationSigners) { + return nil + } + // Acquire a write lock and update the cache with the newly retrieved information + c.lockCache.Lock() + defer c.lockCache.Unlock() + c.applications = poktApplicationSigners + c.applicationChainMap = applicationChainMap + return nil +} + +// StartCacheUpdater starts a goroutine to periodically update the application cache. +func (c *CachedRegistry) startCacheUpdater() { + ticker := time.Tick(applicationUpdateInterval) + go func() { + for { + select { + case <-ticker: + // Call the updateApplicationCache method + err := c.updateApplicationCache() + if err != nil { + c.logger.Sugar().Warnw("failed to update application cache", "err", err) + } else { + c.logger.Sugar().Infow("successfully updated application registry", "applicationsLength", len(c.applications)) + } + } + } + }() +} + +// arePoktApplicationSignersEqual checks if two slices of PoktApplicationSigner are equal. +func arePoktApplicationSignersEqual(slice1, slice2 []*models.PoktApplicationSigner) bool { + // Check if the lengths are different + if len(slice1) != len(slice2) { + return false + } + // Create sorted copies of the slices without modifying the original slices to prevent any latency delays with main relay function + sortedSlice1 := make([]*models.PoktApplicationSigner, len(slice1)) + copy(sortedSlice1, slice1) + sort.Slice(sortedSlice1, func(i, j int) bool { + return sortedSlice1[i].PoktApplication.Address < sortedSlice1[j].PoktApplication.Address + }) + + sortedSlice2 := make([]*models.PoktApplicationSigner, len(slice2)) + copy(sortedSlice2, slice2) + sort.Slice(sortedSlice2, func(i, j int) bool { + return sortedSlice2[i].PoktApplication.Address < sortedSlice2[j].PoktApplication.Address + }) + + // Now that slices are sorted, check if address keys are same. + for i := range slice1 { + // Check if any field is different + if !strings.EqualFold(sortedSlice1[i].PoktApplication.Address, sortedSlice2[i].PoktApplication.Address) { + return false + } + } + + // Slices are equal + return true +} diff --git a/internal/pokt_applications_registry/service.go b/internal/pokt_applications_registry/service.go new file mode 100644 index 0000000..47251a8 --- /dev/null +++ b/internal/pokt_applications_registry/service.go @@ -0,0 +1,8 @@ +package pokt_applications_registry + +import "pokt_gateway_server/internal/pokt_applications_registry/models" + +type Service interface { + GetApplications() []*models.PoktApplicationSigner + GetApplicationsByChainId(chainId string) ([]*models.PoktApplicationSigner, bool) +} diff --git a/internal/pokt_client_decorators/cached_client.go b/internal/pokt_client_decorators/cached_client.go index 9a908a4..dce5e16 100644 --- a/internal/pokt_client_decorators/cached_client.go +++ b/internal/pokt_client_decorators/cached_client.go @@ -3,9 +3,9 @@ package pokt_client_decorators import ( "errors" "github.com/prometheus/client_golang/prometheus" - "os-gateway/pkg/pokt/pokt_v0" - "os-gateway/pkg/pokt/pokt_v0/models" - "os-gateway/pkg/ttl_cache" + "pokt_gateway_server/pkg/pokt/pokt_v0" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/ttl_cache" "strconv" "time" diff --git a/internal/pokt_client_decorators/cached_client_test.go b/internal/pokt_client_decorators/cached_client_test.go index b297c43..794e2d5 100644 --- a/internal/pokt_client_decorators/cached_client_test.go +++ b/internal/pokt_client_decorators/cached_client_test.go @@ -3,8 +3,8 @@ package pokt_client_decorators // Basic imports import ( "errors" - "os-gateway/mocks" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/mocks" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "testing" "time" diff --git a/migrationfs.go b/migrationfs.go new file mode 100644 index 0000000..010a166 --- /dev/null +++ b/migrationfs.go @@ -0,0 +1,6 @@ +package os_gateway + +import "embed" + +//go:embed db_migrations +var Migrations embed.FS diff --git a/mocks/pocket_service_mock.go b/mocks/pocket_service_mock.go index 466293c..7577249 100644 --- a/mocks/pocket_service_mock.go +++ b/mocks/pocket_service_mock.go @@ -3,7 +3,7 @@ package mocks import ( - models "os-gateway/pkg/pokt/pokt_v0/models" + models "pokt_gateway_server/pkg/pokt/pokt_v0/models" mock "github.com/stretchr/testify/mock" ) diff --git a/pkg/common/crypto.go b/pkg/common/crypto.go index d180119..5325fa6 100644 --- a/pkg/common/crypto.go +++ b/pkg/common/crypto.go @@ -1,6 +1,7 @@ package common import ( + "crypto/sha256" "encoding/hex" "github.com/pquerna/ffjson/ffjson" "golang.org/x/crypto/sha3" @@ -22,7 +23,7 @@ func GetAddressFromPublicKey(publicKey string) (string, error) { if err != nil { return "", err } - hasher := sha3.New256() + hasher := sha256.New() hasher.Write(bytes) hashBytes := hasher.Sum(nil) address := hex.EncodeToString(hashBytes) diff --git a/pkg/pokt/pokt_v0/basic_client.go b/pkg/pokt/pokt_v0/basic_client.go index 2993c8e..f94cc6f 100644 --- a/pkg/pokt/pokt_v0/basic_client.go +++ b/pkg/pokt/pokt_v0/basic_client.go @@ -1,11 +1,12 @@ package pokt_v0 import ( + "errors" "github.com/pquerna/ffjson/ffjson" "github.com/valyala/fasthttp" "math/rand" - "os-gateway/pkg/common" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/common" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "time" ) @@ -15,6 +16,8 @@ const ( endpointDispatch = endpointClientPrefix + "/dispatch" endpointSendRelay = endpointClientPrefix + "/relay" endpointGetHeight = endpointQueryPrefix + "/height" + endpointGetApps = endpointQueryPrefix + "/apps" + maxApplications = 5000 ) // BasicClient represents a basic client with a logging, full node host, and a global request timeout. @@ -58,6 +61,27 @@ func (r BasicClient) GetSession(req *models.GetSessionRequest) (*models.GetSessi return &sessionResponse, nil } +// GetLatestStakedApplications obtains all the applications from the latest block then filters for staked. +// Returns: +// - ([]*models.PoktApplication): list of staked applications +// - (error): Error, if any. +func (r BasicClient) GetLatestStakedApplications() ([]*models.PoktApplication, error) { + reqParams := map[string]any{"opts": map[string]any{"per_page": maxApplications}} + var resp models.GetApplicationResponse + err := r.makeRequest(endpointGetApps, "POST", reqParams, &resp, nil) + if err != nil { + return nil, err + } + stakedApplications := []*models.PoktApplication{} + for _, app := range resp.Result { + stakedApplications = append(stakedApplications, app) + } + if len(stakedApplications) == 0 { + return nil, errors.New("zero applications found") + } + return stakedApplications, nil +} + // SendRelay sends a relay request to the full node. // Parameters: // - req: SendRelayRequest instance containing the relay request parameters. diff --git a/pkg/pokt/pokt_v0/generate_proof_bytes.go b/pkg/pokt/pokt_v0/generate_proof_bytes.go index c10e8af..b88b0a7 100644 --- a/pkg/pokt/pokt_v0/generate_proof_bytes.go +++ b/pkg/pokt/pokt_v0/generate_proof_bytes.go @@ -2,8 +2,8 @@ package pokt_v0 import ( "encoding/hex" - "os-gateway/pkg/common" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/common" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" ) // generateRelayProof generates a relay proof. diff --git a/pkg/pokt/pokt_v0/generate_proof_bytes_test.go b/pkg/pokt/pokt_v0/generate_proof_bytes_test.go index fbdf398..127ab1b 100644 --- a/pkg/pokt/pokt_v0/generate_proof_bytes_test.go +++ b/pkg/pokt/pokt_v0/generate_proof_bytes_test.go @@ -2,7 +2,7 @@ package pokt_v0 import ( "github.com/stretchr/testify/assert" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "testing" ) diff --git a/pkg/pokt/pokt_v0/get_node_from_request.go b/pkg/pokt/pokt_v0/get_node_from_request.go index 76b0a14..23506df 100644 --- a/pkg/pokt/pokt_v0/get_node_from_request.go +++ b/pkg/pokt/pokt_v0/get_node_from_request.go @@ -1,8 +1,8 @@ package pokt_v0 import ( - "os-gateway/pkg/common" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/common" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "slices" ) diff --git a/pkg/pokt/pokt_v0/get_node_from_request_test.go b/pkg/pokt/pokt_v0/get_node_from_request_test.go index 19aefa3..8b5cbf0 100644 --- a/pkg/pokt/pokt_v0/get_node_from_request_test.go +++ b/pkg/pokt/pokt_v0/get_node_from_request_test.go @@ -1,7 +1,7 @@ package pokt_v0 import ( - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "testing" "github.com/stretchr/testify/assert" diff --git a/pkg/pokt/pokt_v0/get_session_from_request.go b/pkg/pokt/pokt_v0/get_session_from_request.go index 1aefc76..e9d879b 100644 --- a/pkg/pokt/pokt_v0/get_session_from_request.go +++ b/pkg/pokt/pokt_v0/get_session_from_request.go @@ -1,6 +1,6 @@ package pokt_v0 -import "os-gateway/pkg/pokt/pokt_v0/models" +import "pokt_gateway_server/pkg/pokt/pokt_v0/models" // GetSessionFromRequest obtains a session from a relay request. // Parameters: diff --git a/pkg/pokt/pokt_v0/get_session_from_request_test.go b/pkg/pokt/pokt_v0/get_session_from_request_test.go index 83281bf..6b65cef 100644 --- a/pkg/pokt/pokt_v0/get_session_from_request_test.go +++ b/pkg/pokt/pokt_v0/get_session_from_request_test.go @@ -4,8 +4,8 @@ import ( "errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "os-gateway/mocks" - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/mocks" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" "testing" ) diff --git a/pkg/pokt/pokt_v0/models/aat.go b/pkg/pokt/pokt_v0/models/aat.go index e9fb12b..b4719c9 100644 --- a/pkg/pokt/pokt_v0/models/aat.go +++ b/pkg/pokt/pokt_v0/models/aat.go @@ -2,7 +2,7 @@ package models import ( - "os-gateway/pkg/common" + "pokt_gateway_server/pkg/common" ) type AAT struct { diff --git a/pkg/pokt/pokt_v0/models/application.go b/pkg/pokt/pokt_v0/models/application.go new file mode 100644 index 0000000..17ad70e --- /dev/null +++ b/pkg/pokt/pokt_v0/models/application.go @@ -0,0 +1,49 @@ +//go:generate ffjson $GOFILE +package models + +import ( + "encoding/json" + "strconv" +) + +type PoktApplicationStatus uint + +const ( + StatusJailed PoktApplicationStatus = 0 + StatusUnstaking PoktApplicationStatus = 1 + StatusStaked PoktApplicationStatus = 2 +) + +// MaxRelays is a custom type for handling the MaxRelays field. +type MaxRelays int + +// UnmarshalJSON customizes the JSON unmarshalling for MaxRelays. +func (mr *MaxRelays) UnmarshalJSON(data []byte) error { + var maxRelaysString string + if err := json.Unmarshal(data, &maxRelaysString); err != nil { + return err + } + + // Parse the string into an integer + maxRelays, err := strconv.Atoi(maxRelaysString) + if err != nil { + return err + } + + // Set the MaxRelays field with the parsed integer + *mr = MaxRelays(maxRelays) + + return nil +} + +type GetApplicationResponse struct { + Result []*PoktApplication `json:"result"` +} + +type PoktApplication struct { + Address string `json:"address"` + Chains []string `json:"chains"` + PublicKey string `json:"public_key"` + Status PoktApplicationStatus `json:"status"` + MaxRelays MaxRelays `json:"max_relays"` +} diff --git a/pkg/pokt/pokt_v0/models/ed25519-account.go b/pkg/pokt/pokt_v0/models/ed25519-account.go index dabb143..0405dee 100644 --- a/pkg/pokt/pokt_v0/models/ed25519-account.go +++ b/pkg/pokt/pokt_v0/models/ed25519-account.go @@ -5,7 +5,7 @@ import ( "crypto/ed25519" "encoding/hex" "errors" - "os-gateway/pkg/common" + "pokt_gateway_server/pkg/common" "sync" ) diff --git a/pkg/pokt/pokt_v0/models/relay.go b/pkg/pokt/pokt_v0/models/relay.go index a3b3b5f..8cbf262 100644 --- a/pkg/pokt/pokt_v0/models/relay.go +++ b/pkg/pokt/pokt_v0/models/relay.go @@ -2,7 +2,7 @@ package models import ( - "os-gateway/pkg/common" + "pokt_gateway_server/pkg/common" ) type SendRelayRequest struct { diff --git a/pkg/pokt/pokt_v0/service.go b/pkg/pokt/pokt_v0/service.go index fe1ea78..376f446 100644 --- a/pkg/pokt/pokt_v0/service.go +++ b/pkg/pokt/pokt_v0/service.go @@ -1,11 +1,12 @@ package pokt_v0 import ( - "os-gateway/pkg/pokt/pokt_v0/models" + "pokt_gateway_server/pkg/pokt/pokt_v0/models" ) type PocketService interface { GetSession(req *models.GetSessionRequest) (*models.GetSessionResponse, error) SendRelay(req *models.SendRelayRequest) (*models.SendRelayResponse, error) GetLatestBlockHeight() (*models.GetLatestBlockHeightResponse, error) + GetLatestStakedApplications() ([]*models.PoktApplication, error) } diff --git a/scripts/migration.sh b/scripts/migration.sh new file mode 100755 index 0000000..adc17f0 --- /dev/null +++ b/scripts/migration.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Set working directory to one level behind +cd "$(dirname "$0")/.." + +# Parse command line arguments +if [[ $# -eq 0 ]]; then + echo "Error: Missing required argument --name, --up, or --down" + exit 1 +fi + +while [[ $# -gt 0 ]] +do +key="$1" + +case $key in + -n|--name) + NAME="$2" + shift # past argument + shift # past value + ;; + -u|--up) + UP="true" + shift # past argument + ;; + -d|--down) + DOWN="true" + shift # past argument + ;; + *) # unknown option + echo "Unknown option: $1" + exit 1 + ;; +esac +done + +# Load environment variables from .env file located one level behind +if [ -f .env ]; then + export $(cat .env | sed 's/#.*//g' | xargs) +else + echo "Error: .env file not found in parent directory." + exit 1 +fi + + +# Check if migrating up, down, or creating a new migration +if [ "$UP" = "true" ]; then + # Migrate up + migrate -database "$DB_CONNECTION_URL" -path "db_migrations" up 1 +elif [ "$DOWN" = "true" ]; then + # Migrate down + migrate -database "$DB_CONNECTION_URL" -path "db_migrations" down 1 +else + # Create new migration + if [ -z "$NAME" ]; then + echo "Error: Missing required argument --name" + exit 1 + fi + migrate -database "$DB_CONNECTION_URL" create -ext sql -seq -dir "db_migrations" "$NAME" +fi \ No newline at end of file diff --git a/scripts/querygen.sh b/scripts/querygen.sh new file mode 100755 index 0000000..2ae2904 --- /dev/null +++ b/scripts/querygen.sh @@ -0,0 +1,16 @@ +# Set working directory to one level behind +cd "$(dirname "$0")/.." + +# Load environment variables from .env file located one level behind +if [ -f .env ]; then + export $(cat .env | sed 's/#.*//g' | xargs) +else + echo "Error: .env file not found in parent directory." + exit 1 +fi + +pggen gen go \ + --postgres-connection "$DB_CONNECTION_URL" \ + --query-glob internal/db_query/*.sql \ + --go-type 'int8=int' \ + --go-type 'text=string' \ No newline at end of file