diff --git a/cmd/cartesi-rollups-cli/root/db/check/check.go b/cmd/cartesi-rollups-cli/root/db/check/check.go index 3c5fc7df8..95aa5d2d6 100644 --- a/cmd/cartesi-rollups-cli/root/db/check/check.go +++ b/cmd/cartesi-rollups-cli/root/db/check/check.go @@ -3,10 +3,10 @@ package check import ( - "fmt" + "log/slog" "github.com/cartesi/rollups-node/cmd/cartesi-rollups-cli/root/common" - "github.com/cartesi/rollups-node/internal/repository" + "github.com/cartesi/rollups-node/internal/repository/schema" "github.com/spf13/cobra" ) @@ -17,13 +17,12 @@ var Cmd = &cobra.Command{ } func run(cmd *cobra.Command, args []string) { - - schemaManager, err := repository.NewSchemaManager(common.PostgresEndpoint) + schema, err := schema.New(common.PostgresEndpoint) cobra.CheckErr(err) - defer schemaManager.Close() + defer schema.Close() - err = schemaManager.ValidateSchemaVersion() + version, err := schema.ValidateVersion() cobra.CheckErr(err) - fmt.Printf("Database Schema is at the correct version: %d\n", repository.EXPECTED_VERSION) + slog.Info("Database Schema is at the correct version.", "version", version) } diff --git a/cmd/cartesi-rollups-cli/root/db/upgrade/upgrade.go b/cmd/cartesi-rollups-cli/root/db/upgrade/upgrade.go index 6783cccd7..f1651d232 100644 --- a/cmd/cartesi-rollups-cli/root/db/upgrade/upgrade.go +++ b/cmd/cartesi-rollups-cli/root/db/upgrade/upgrade.go @@ -3,11 +3,10 @@ package upgrade import ( - "fmt" "log/slog" "github.com/cartesi/rollups-node/cmd/cartesi-rollups-cli/root/common" - "github.com/cartesi/rollups-node/internal/repository" + "github.com/cartesi/rollups-node/internal/repository/schema" "github.com/spf13/cobra" ) @@ -18,21 +17,15 @@ var Cmd = &cobra.Command{ } func run(cmd *cobra.Command, args []string) { - - schemaManager, err := repository.NewSchemaManager(common.PostgresEndpoint) + schema, err := schema.New(common.PostgresEndpoint) cobra.CheckErr(err) - defer schemaManager.Close() + defer schema.Close() - err = schemaManager.Upgrade() + err = schema.Upgrade() cobra.CheckErr(err) - version, err := schemaManager.GetVersion() + version, err := schema.ValidateVersion() cobra.CheckErr(err) - if repository.EXPECTED_VERSION != version { - slog.Warn("Current version is different to expected one") - } - - fmt.Printf("Database Schema successfully Updated. Current version is %d\n", version) - + slog.Info("Database Schema successfully Updated.", "version", version) } diff --git a/internal/node/startup/startup.go b/internal/node/startup/startup.go index 09d54ec40..2dbbfdad5 100644 --- a/internal/node/startup/startup.go +++ b/internal/node/startup/startup.go @@ -12,6 +12,7 @@ import ( "github.com/cartesi/rollups-node/internal/node/config" "github.com/cartesi/rollups-node/internal/node/model" "github.com/cartesi/rollups-node/internal/repository" + "github.com/cartesi/rollups-node/internal/repository/schema" "github.com/ethereum/go-ethereum/common" "github.com/jackc/pgx/v5" "github.com/lmittmann/tint" @@ -20,31 +21,19 @@ import ( // Validates the Node Database Schema Version func ValidateSchema(config config.NodeConfig) error { - var ( - schemaManager *repository.SchemaManager - err error - ) - - if !config.PostgresSslMode { - schemaManager, err = repository.NewSchemaManager( - fmt.Sprintf("%v?sslmode=disable", config.PostgresEndpoint.Value)) - if err != nil { - return err - } - } else { - schemaManager, err = repository.NewSchemaManager(config.PostgresEndpoint.Value) - if err != nil { - return err - } + endpoint := config.PostgresEndpoint.Value + if config.PostgresSslMode { + endpoint += "?sslmode=disable" } - defer schemaManager.Close() - err = schemaManager.ValidateSchemaVersion() + + schema, err := schema.New(endpoint) if err != nil { return err } + defer schema.Close() - return nil - + _, err = schema.ValidateVersion() + return err } // Configure the node logs diff --git a/internal/repository/migrations/000001_create_application_input_claim_output_report_nodeconfig.down.sql b/internal/repository/schema/migrations/000001_create_application_input_claim_output_report_nodeconfig.down.sql similarity index 92% rename from internal/repository/migrations/000001_create_application_input_claim_output_report_nodeconfig.down.sql rename to internal/repository/schema/migrations/000001_create_application_input_claim_output_report_nodeconfig.down.sql index 2c4628a58..62147fc4b 100644 --- a/internal/repository/migrations/000001_create_application_input_claim_output_report_nodeconfig.down.sql +++ b/internal/repository/schema/migrations/000001_create_application_input_claim_output_report_nodeconfig.down.sql @@ -9,6 +9,7 @@ DROP TABLE IF EXISTS "input"; DROP TABLE IF EXISTS "epoch"; DROP TABLE IF EXISTS "application"; +DROP FUNCTION IF EXISTS "f_maxuint64"; DROP TYPE IF EXISTS "InputCompletionStatus"; DROP TYPE IF EXISTS "ApplicationStatus"; diff --git a/internal/repository/migrations/000001_create_application_input_claim_output_report_nodeconfig.up.sql b/internal/repository/schema/migrations/000001_create_application_input_claim_output_report_nodeconfig.up.sql similarity index 84% rename from internal/repository/migrations/000001_create_application_input_claim_output_report_nodeconfig.up.sql rename to internal/repository/schema/migrations/000001_create_application_input_claim_output_report_nodeconfig.up.sql index b62f17042..5bce75001 100644 --- a/internal/repository/migrations/000001_create_application_input_claim_output_report_nodeconfig.up.sql +++ b/internal/repository/schema/migrations/000001_create_application_input_claim_output_report_nodeconfig.up.sql @@ -3,16 +3,31 @@ CREATE TYPE "ApplicationStatus" AS ENUM ('RUNNING', 'NOT RUNNING'); -CREATE TYPE "InputCompletionStatus" AS ENUM ('NONE', 'ACCEPTED', 'REJECTED', 'EXCEPTION', 'MACHINE_HALTED', 'CYCLE_LIMIT_EXCEEDED', 'TIME_LIMIT_EXCEEDED', 'PAYLOAD_LENGTH_LIMIT_EXCEEDED'); +CREATE TYPE "InputCompletionStatus" AS ENUM ( + 'NONE', + 'ACCEPTED', + 'REJECTED', + 'EXCEPTION', + 'MACHINE_HALTED', + 'CYCLE_LIMIT_EXCEEDED', + 'TIME_LIMIT_EXCEEDED', + 'PAYLOAD_LENGTH_LIMIT_EXCEEDED'); CREATE TYPE "DefaultBlock" AS ENUM ('FINALIZED', 'LATEST', 'PENDING', 'SAFE'); -CREATE TYPE "EpochStatus" AS ENUM ('OPEN', 'CLOSED', 'PROCESSED_ALL_INPUTS', 'CLAIM_COMPUTED', 'CLAIM_SUBMITTED', 'CLAIM_ACCEPTED', 'CLAIM_REJECTED'); +CREATE TYPE "EpochStatus" AS ENUM ( + 'OPEN', + 'CLOSED', + 'PROCESSED_ALL_INPUTS', + 'CLAIM_COMPUTED', + 'CLAIM_SUBMITTED', + 'CLAIM_ACCEPTED', + 'CLAIM_REJECTED'); -CREATE FUNCTION public.f_maxuint64() - RETURNS NUMERIC(20,0) - LANGUAGE sql IMMUTABLE PARALLEL SAFE AS -'SELECT 18446744073709551615'; +CREATE FUNCTION "f_maxuint64"() + RETURNS NUMERIC(20,0) + LANGUAGE sql IMMUTABLE PARALLEL SAFE AS + 'SELECT 18446744073709551615'; CREATE TABLE "application" ( @@ -72,7 +87,7 @@ CREATE TABLE "output" CONSTRAINT "output_input_id_fkey" FOREIGN KEY ("input_id") REFERENCES "input"("id") ); -CREATE UNIQUE INDEX "output_idx" ON "output"("index"); +CREATE INDEX "output_idx" ON "output"("index"); CREATE TABLE "report" ( @@ -84,7 +99,7 @@ CREATE TABLE "report" CONSTRAINT "report_input_id_fkey" FOREIGN KEY ("input_id") REFERENCES "input"("id") ); -CREATE UNIQUE INDEX "report_idx" ON "report"("index"); +CREATE INDEX "report_idx" ON "report"("index"); CREATE TABLE "snapshot" ( diff --git a/internal/repository/migrations/000002_create_postgraphile_view.down.sql b/internal/repository/schema/migrations/000002_create_postgraphile_view.down.sql similarity index 78% rename from internal/repository/migrations/000002_create_postgraphile_view.down.sql rename to internal/repository/schema/migrations/000002_create_postgraphile_view.down.sql index 0ba224155..4fc005d2a 100644 --- a/internal/repository/migrations/000002_create_postgraphile_view.down.sql +++ b/internal/repository/schema/migrations/000002_create_postgraphile_view.down.sql @@ -1,4 +1,4 @@ -- (c) Cartesi and individual authors (see AUTHORS) -- SPDX-License-Identifier: Apache-2.0 (see LICENSE) -DROP SCHEMA graphql CASCADE; \ No newline at end of file +DROP SCHEMA graphql CASCADE; diff --git a/internal/repository/migrations/000002_create_postgraphile_view.up.sql b/internal/repository/schema/migrations/000002_create_postgraphile_view.up.sql similarity index 100% rename from internal/repository/migrations/000002_create_postgraphile_view.up.sql rename to internal/repository/schema/migrations/000002_create_postgraphile_view.up.sql diff --git a/internal/repository/schema/schema.go b/internal/repository/schema/schema.go new file mode 100644 index 000000000..ccc6742ef --- /dev/null +++ b/internal/repository/schema/schema.go @@ -0,0 +1,85 @@ +// (c) Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 (see LICENSE) + +package schema + +import ( + "embed" + "errors" + "fmt" + "log/slog" + + "github.com/golang-migrate/migrate/v4" + mig "github.com/golang-migrate/migrate/v4" + _ "github.com/golang-migrate/migrate/v4/database/postgres" + _ "github.com/golang-migrate/migrate/v4/source/file" + "github.com/golang-migrate/migrate/v4/source/iofs" +) + +//go:embed migrations/* +var content embed.FS + +const ExpectedVersion uint = 2 + +type Schema struct { + migrate *mig.Migrate +} + +func New(postgresEndpoint string) (*Schema, error) { + driver, err := iofs.New(content, "migrations") + if err != nil { + return nil, err + } + + migrate, err := mig.NewWithSourceInstance("iofs", driver, postgresEndpoint) + if err != nil { + return nil, err + } + + return &Schema{migrate: migrate}, nil +} + +func (s *Schema) Version() (uint, error) { + version, _, err := s.migrate.Version() + if err != nil && errors.Is(err, migrate.ErrNilVersion) { + return version, fmt.Errorf("No valid database schema found") + } + return version, err +} + +func (s *Schema) Upgrade() error { + if err := s.migrate.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) { + return err + } + return nil +} + +func (s *Schema) Downgrade() error { + if err := s.migrate.Down(); err != nil && !errors.Is(err, migrate.ErrNoChange) { + return err + } + return nil +} + +func (s *Schema) Close() { + source, db := s.migrate.Close() + if source != nil { + slog.Error("Error releasing migration sources", "error", source) + } + if db != nil { + slog.Error("Error closing db connection", "error", db) + } +} + +func (s *Schema) ValidateVersion() (uint, error) { + version, err := s.Version() + if err != nil { + return 0, err + } + + if version != ExpectedVersion { + format := "Database schema version mismatch. Expected %d but it is %d" + return 0, fmt.Errorf(format, ExpectedVersion, version) + } + return version, nil +} diff --git a/internal/repository/schemamanager.go b/internal/repository/schemamanager.go deleted file mode 100644 index 4c271b39c..000000000 --- a/internal/repository/schemamanager.go +++ /dev/null @@ -1,102 +0,0 @@ -// (c) Cartesi and individual authors (see AUTHORS) -// SPDX-License-Identifier: Apache-2.0 (see LICENSE) - -package repository - -import ( - "embed" - "errors" - "fmt" - "log/slog" - - "github.com/golang-migrate/migrate/v4" - mig "github.com/golang-migrate/migrate/v4" - _ "github.com/golang-migrate/migrate/v4/database/postgres" - _ "github.com/golang-migrate/migrate/v4/source/file" - "github.com/golang-migrate/migrate/v4/source/iofs" -) - -//go:embed migrations/* -var content embed.FS - -const ( - EXPECTED_VERSION = 2 -) - -type ( - Migrate = mig.Migrate -) - -type SchemaManager struct { - migrate *Migrate -} - -func NewSchemaManager(postgresEndpoint string) (*SchemaManager, error) { - - driver, err := iofs.New(content, "migrations") - if err != nil { - return nil, err - } - - migrate, err := mig.NewWithSourceInstance( - "iofs", - driver, - postgresEndpoint, - ) - if err != nil { - return nil, err - } - return &SchemaManager{ - migrate: migrate, - }, nil - -} - -func (s *SchemaManager) GetVersion() (uint, error) { - - version, _, err := s.migrate.Version() - - if err != nil { - if errors.Is(err, migrate.ErrNilVersion) { - return version, fmt.Errorf("No valid database schema found") - } - } - - return version, err - -} - -func (s *SchemaManager) Upgrade() error { - if err := s.migrate.Up(); err != nil { - if !errors.Is(err, migrate.ErrNoChange) { - return err - } - } - return nil -} - -func (s *SchemaManager) Close() { - source, db := s.migrate.Close() - if source != nil { - slog.Error("Error releasing migration sources", "error", source) - } - if db != nil { - slog.Error("Error closing db connection", "error", db) - } -} - -func (s *SchemaManager) ValidateSchemaVersion() error { - version, err := s.GetVersion() - if err != nil { - return err - } - - if version != EXPECTED_VERSION { - return fmt.Errorf( - "Database schema version mismatch. Expected %d but it is %d", - EXPECTED_VERSION, - version, - ) - } - return nil -}