diff --git a/cmd/cartesi-rollups-advancer/root/root.go b/cmd/cartesi-rollups-advancer/root/root.go index 8b8068610..fa405e2d4 100644 --- a/cmd/cartesi-rollups-advancer/root/root.go +++ b/cmd/cartesi-rollups-advancer/root/root.go @@ -4,104 +4,42 @@ package root import ( - "context" - "fmt" - "log/slog" - "net/http" - "os/signal" - "syscall" - "github.com/cartesi/rollups-node/internal/advancer" - "github.com/cartesi/rollups-node/internal/advancer/config" - "github.com/cartesi/rollups-node/internal/advancer/machines" - "github.com/cartesi/rollups-node/internal/inspect" - "github.com/cartesi/rollups-node/internal/repository" - "github.com/cartesi/rollups-node/internal/services" - "github.com/cartesi/rollups-node/internal/services/startup" - + "github.com/cartesi/rollups-node/pkg/service" "github.com/spf13/cobra" ) -const CMD_NAME = "advancer" - var ( - buildVersion = "devel" - Cmd = &cobra.Command{ - Use: CMD_NAME, - Short: "Runs the Advancer", - Long: "Runs the Advancer in standalone mode", - RunE: run, + buildVersion = "devel" + advancerService = advancer.Service{} + createInfo = advancer.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "advancer", + ProcOwner: true, + EnableSignalHandling: true, + TelemetryCreate: true, + TelemetryAddress: ":10001", + Impl: &advancerService, + }, } ) -func getDatabase(ctx context.Context, endpoint string) (*repository.Database, error) { - database, err := repository.Connect(ctx, endpoint) - if err != nil { - return nil, fmt.Errorf("failed to connect to the database: %w", err) - } - - return database, nil +var Cmd = &cobra.Command{ + Use: createInfo.Name, + Short: "Runs " + createInfo.Name, + Long: "Runs " + createInfo.Name + " in standalone mode", + Run: run, } -func healthcheckHandler(w http.ResponseWriter, r *http.Request) { - slog.Debug("Advancer received a healthcheck request") - w.WriteHeader(http.StatusOK) +func init() { + createInfo.LoadEnv() + Cmd.Flags().Var(&createInfo.LogLevel, + "log-level", + "log level: debug, info, warn or error") } -func run(cmd *cobra.Command, args []string) error { - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() - - c := config.GetAdvancerConfig() - startup.ConfigLogs(c.LogLevel, c.LogPrettyEnabled) - - slog.Info("Starting the Cartesi Rollups Node Advancer", "version", buildVersion, "config", c) - - database, err := getDatabase(ctx, c.PostgresEndpoint.Value) - if err != nil { - return err - } - defer database.Close() - - repo := &repository.MachineRepository{Database: database} - - machines, err := machines.Load(ctx, repo, c.MachineServerVerbosity) - if err != nil { - return fmt.Errorf("failed to load the machines: %w", err) - } - defer machines.Close() - - inspector, err := inspect.New(machines) - if err != nil { - return fmt.Errorf("failed to create the inspector: %w", err) - } - - advancer, err := advancer.New(machines, repo) - if err != nil { - return fmt.Errorf("failed to create the advancer: %w", err) - } - - poller, err := advancer.Poller(c.AdvancerPollingInterval) - if err != nil { - return fmt.Errorf("failed to create the advancer service: %w", err) - } - - serveMux := http.NewServeMux() - serveMux.Handle("/healthz", http.HandlerFunc(healthcheckHandler)) - serveMux.Handle("/inspect/{dapp}", http.Handler(inspector)) - serveMux.Handle("/inspect/{dapp}/{payload}", http.Handler(inspector)) - - httpServer := &http.Server{ - Addr: fmt.Sprintf("%v:%v", c.HttpAddress, c.HttpPort), - Handler: services.CorsMiddleware(serveMux), - } - - go func() { - if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { - slog.Error("Could not listen on %s: %v\n", httpServer.Addr, err) - stop() - } - }() - - return poller.Start(ctx) +func run(cmd *cobra.Command, args []string) { + cobra.CheckErr(advancer.Create(&createInfo, &advancerService)) + advancerService.CreateDefaultHandlers("/" + advancerService.Name) + cobra.CheckErr(advancerService.Serve()) } diff --git a/cmd/cartesi-rollups-claimer/root/root.go b/cmd/cartesi-rollups-claimer/root/root.go index a94a639f1..af357f090 100644 --- a/cmd/cartesi-rollups-claimer/root/root.go +++ b/cmd/cartesi-rollups-claimer/root/root.go @@ -17,7 +17,6 @@ var ( createInfo = claimer.CreateInfo{ CreateInfo: service.CreateInfo{ Name: "claimer", - LogLevel: "info", ProcOwner: true, EnableSignalHandling: true, TelemetryCreate: true, @@ -46,8 +45,8 @@ func init() { Cmd.Flags().DurationVar(&createInfo.PollInterval, "poll-interval", createInfo.PollInterval, "poll interval") - Cmd.Flags().StringVar(&createInfo.LogLevel, - "log-level", createInfo.LogLevel, + Cmd.Flags().Var(&createInfo.LogLevel, + "log-level", "log level: debug, info, warn or error") Cmd.Flags().BoolVar(&createInfo.EnableSubmission, "claim-submission", createInfo.EnableSubmission, diff --git a/cmd/cartesi-rollups-evm-reader/root/root.go b/cmd/cartesi-rollups-evm-reader/root/root.go index 5a57d76eb..c4b81edad 100644 --- a/cmd/cartesi-rollups-evm-reader/root/root.go +++ b/cmd/cartesi-rollups-evm-reader/root/root.go @@ -4,17 +4,8 @@ package root import ( - "context" - "log/slog" - "os" - "os/signal" - "syscall" - "time" - - "github.com/cartesi/rollups-node/internal/config" - "github.com/cartesi/rollups-node/internal/evmreader/service" - "github.com/cartesi/rollups-node/internal/repository" - "github.com/cartesi/rollups-node/internal/services/startup" + "github.com/cartesi/rollups-node/internal/evmreader" + "github.com/cartesi/rollups-node/pkg/service" "github.com/spf13/cobra" ) @@ -22,143 +13,73 @@ import ( var ( // Should be overridden during the final release build with ldflags // to contain the actual version number - buildVersion = "devel" -) - -const ( - CMD_NAME = "evm-reader" + buildVersion = "devel" + readerService = evmreader.Service{} + createInfo = evmreader.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "evm-reader", + ProcOwner: true, + EnableSignalHandling: true, + TelemetryCreate: true, + TelemetryAddress: ":10000", + Impl: &readerService, + }, + DefaultBlockString: "safe", + } ) var Cmd = &cobra.Command{ - Use: CMD_NAME, - Short: "Runs EVM Reader", - Long: `Runs EVM Reader in standalone mode`, + Use: createInfo.Name, + Short: "Runs " + createInfo.Name, + Long: "Runs " + createInfo.Name + " in standalone mode", Run: run, } -var ( - defaultBlock string - postgresEndpoint string - blockchainHttpEndpoint string - blockchainWsEndpoint string - inputBoxAddress string - inputBoxDeploymentBlockNumber uint64 - verbose bool -) func init() { + createInfo.LoadEnv() - Cmd.Flags().StringVarP(&defaultBlock, - "default-block", - "d", - "", + Cmd.Flags().StringVarP(&createInfo.DefaultBlockString, + "default-block", "d", createInfo.DefaultBlockString, `Default block to be used when fetching new blocks. One of 'latest', 'safe', 'pending', 'finalized'`) - Cmd.Flags().StringVarP(&postgresEndpoint, + Cmd.Flags().StringVarP(&createInfo.PostgresEndpoint.Value, "postgres-endpoint", "p", - "", + createInfo.PostgresEndpoint.Value, "Postgres endpoint") - Cmd.Flags().StringVarP(&blockchainHttpEndpoint, + Cmd.Flags().StringVarP(&createInfo.BlockchainHttpEndpoint.Value, "blockchain-http-endpoint", "b", - "", + createInfo.BlockchainHttpEndpoint.Value, "Blockchain HTTP Endpoint") - Cmd.Flags().StringVarP(&blockchainWsEndpoint, + Cmd.Flags().StringVarP(&createInfo.BlockchainWsEndpoint.Value, "blockchain-ws-endpoint", "w", - "", + createInfo.BlockchainWsEndpoint.Value, "Blockchain WS Endpoint") - Cmd.Flags().StringVarP(&inputBoxAddress, - "inputbox-address", - "i", - "", - "Input Box contract address") +// Cmd.Flags().StringVarP(&inputBoxAddress, +// "inputbox-address", +// "i", +// "", +// "Input Box contract address") - Cmd.Flags().Uint64VarP(&inputBoxDeploymentBlockNumber, + Cmd.Flags().Uint64VarP(&createInfo.InputBoxDeploymentBlock, "inputbox-block-number", "n", 0, "Input Box deployment block number") - - Cmd.Flags().BoolVarP(&verbose, - "verbose", - "v", - false, - "enable verbose logging") + Cmd.Flags().Var(&createInfo.LogLevel, + "log-level", + "log level: debug, info, warn or error") } func run(cmd *cobra.Command, args []string) { - startTime := time.Now() - - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() - - c := config.FromEnv() - - // Override configs - if verbose { - c.LogLevel = slog.LevelDebug - } - if postgresEndpoint != "" { - c.PostgresEndpoint = config.Redacted[string]{Value: postgresEndpoint} - } - if blockchainHttpEndpoint != "" { - c.BlockchainHttpEndpoint = config.Redacted[string]{Value: blockchainHttpEndpoint} - } - if blockchainWsEndpoint != "" { - c.BlockchainWsEndpoint = config.Redacted[string]{Value: blockchainWsEndpoint} - } - if defaultBlock != "" { - evmReaderDefaultBlock, err := config.ToDefaultBlockFromString(defaultBlock) - cobra.CheckErr(err) - c.EvmReaderDefaultBlock = evmReaderDefaultBlock - } - - // setup log - startup.ConfigLogs(c.LogLevel, c.LogPrettyEnabled) - - slog.Info("Starting the Cartesi Rollups Node EVM Reader", "version", buildVersion, "config", c) - - database, err := repository.Connect(ctx, c.PostgresEndpoint.Value) - if err != nil { - slog.Error("EVM Reader couldn't connect to the database", "error", err) - os.Exit(1) - } - defer database.Close() - - _, err = startup.SetupNodePersistentConfig(ctx, database, c) - if err != nil { - slog.Error("EVM Reader couldn't connect to the database", "error", err) - os.Exit(1) - } - - // create EVM Reader Service - service := service.NewEvmReaderService( - c.BlockchainHttpEndpoint.Value, - c.BlockchainWsEndpoint.Value, - database, - c.EvmReaderRetryPolicyMaxRetries, - c.EvmReaderRetryPolicyMaxDelay, - ) - - // logs startup time ready := make(chan struct{}, 1) - go func() { - select { - case <-ready: - duration := time.Since(startTime) - slog.Info("EVM Reader is ready", "after", duration) - case <-ctx.Done(): - } - }() - - // start service - if err := service.Start(ctx, ready); err != nil { - slog.Error("EVM Reader exited with an error", "error", err) - os.Exit(1) - } + cobra.CheckErr(evmreader.Create(&createInfo, &readerService)) + readerService.CreateDefaultHandlers("/" + readerService.Name) + cobra.CheckErr(readerService.Start(nil, ready)) } diff --git a/cmd/cartesi-rollups-node/root/root.go b/cmd/cartesi-rollups-node/root/root.go index 67b5fe45d..3191fb93e 100644 --- a/cmd/cartesi-rollups-node/root/root.go +++ b/cmd/cartesi-rollups-node/root/root.go @@ -14,7 +14,6 @@ import ( "github.com/cartesi/rollups-node/internal/config" "github.com/cartesi/rollups-node/internal/node" "github.com/cartesi/rollups-node/internal/repository" - "github.com/cartesi/rollups-node/internal/services/startup" "github.com/spf13/cobra" ) @@ -53,10 +52,6 @@ func run(cmd *cobra.Command, args []string) error { } } - // setup log - startup.ConfigLogs(cfg.LogLevel, cfg.LogPrettyEnabled) - slog.Info("Starting the Cartesi Rollups Node", "version", buildVersion, "config", cfg) - database, err := repository.Connect(ctx, cfg.PostgresEndpoint.Value) if err != nil { slog.Error("Node couldn't connect to the database", "error", err) @@ -64,12 +59,6 @@ func run(cmd *cobra.Command, args []string) error { } defer database.Close() - _, err = startup.SetupNodePersistentConfig(ctx, database, cfg) - if err != nil { - slog.Error("Node exited with an error", "error", err) - os.Exit(1) - } - // create the node supervisor supervisor, err := node.Setup(ctx, cfg, database) if err != nil { diff --git a/cmd/cartesi-rollups-validator/root/root.go b/cmd/cartesi-rollups-validator/root/root.go index 4a558b89a..adc5d7ca0 100644 --- a/cmd/cartesi-rollups-validator/root/root.go +++ b/cmd/cartesi-rollups-validator/root/root.go @@ -4,112 +4,53 @@ package root import ( - "context" - "log/slog" - "os" - "os/signal" - "syscall" - "time" - - "github.com/cartesi/rollups-node/internal/config" - "github.com/cartesi/rollups-node/internal/repository" - "github.com/cartesi/rollups-node/internal/services/startup" "github.com/cartesi/rollups-node/internal/validator" + "github.com/cartesi/rollups-node/pkg/service" "github.com/spf13/cobra" ) const CMD_NAME = "validator" var ( - buildVersion = "devel" - Cmd = &cobra.Command{ - Use: CMD_NAME, - Short: "Runs Validator", - Long: "Runs Validator in standalone mode", - Run: run, + buildVersion = "devel" + validatorService = validator.Service{} + createInfo = validator.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "validator", + ProcOwner: true, + EnableSignalHandling: true, + TelemetryCreate: true, + TelemetryAddress: ":10002", + Impl: &validatorService, + }, } - inputBoxDeploymentBlockNumber int64 - pollingInterval int64 - postgresEndpoint string - verbose bool ) +var Cmd = &cobra.Command{ + Use: createInfo.Name, + Short: "Runs Validator", + Long: "Runs Validator in standalone mode", + Run: run, +} + func init() { - Cmd.Flags().Int64VarP(&inputBoxDeploymentBlockNumber, - "inputbox-block-number", - "n", - -1, - "Input Box deployment block number", - ) - Cmd.Flags().Int64VarP( - &pollingInterval, - "polling-interval", - "", - -1, - "the amount of seconds to wait before trying to finish epochs for all applications", - ) - Cmd.Flags().StringVarP(&postgresEndpoint, "postgres-endpoint", "p", "", "Postgres endpoint") - Cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "enable verbose logging") + createInfo.LoadEnv() + Cmd.Flags().StringVar(&createInfo.TelemetryAddress, + "telemetry-address", createInfo.TelemetryAddress, + "health check and metrics address and port") + Cmd.Flags().DurationVar(&createInfo.PollInterval, + "poll-interval", createInfo.PollInterval, + "poll interval") + Cmd.Flags().Var(&createInfo.LogLevel, + "log-level", + "log level: debug, info, warn or error") + Cmd.Flags().StringVar(&createInfo.PostgresEndpoint.Value, + "postgres-endpoint", createInfo.PostgresEndpoint.Value, + "Postgres endpoint") } func run(cmd *cobra.Command, args []string) { - startTime := time.Now() - - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() - - c := config.FromEnv() - - // Override configs - if inputBoxDeploymentBlockNumber >= 0 { - c.ContractsInputBoxDeploymentBlockNumber = inputBoxDeploymentBlockNumber - } - if pollingInterval > 0 { - c.ValidatorPollingInterval = time.Duration(pollingInterval) * time.Second - } - if verbose { - c.LogLevel = slog.LevelDebug - } - if postgresEndpoint != "" { - c.PostgresEndpoint = config.Redacted[string]{Value: postgresEndpoint} - } - - startup.ConfigLogs(c.LogLevel, c.LogPrettyEnabled) - - slog.Info("Starting the Cartesi Rollups Node Validator", "version", buildVersion, "config", c) - - database, err := repository.Connect(ctx, c.PostgresEndpoint.Value) - if err != nil { - slog.Error("failed to connect to the database", "error", err) - os.Exit(1) - } - defer database.Close() - - _, err = startup.SetupNodePersistentConfig(ctx, database, c) - if err != nil { - slog.Error("configuration error", "error", err) - os.Exit(1) - } - - service := validator.NewValidatorService( - database, - uint64(c.ContractsInputBoxDeploymentBlockNumber), - c.ValidatorPollingInterval, - ) - - ready := make(chan struct{}, 1) - go func() { - select { - case <-ready: - duration := time.Since(startTime) - slog.Info("validator is ready", "after", duration) - case <-ctx.Done(): - } - }() - - // start service - if err := service.Start(ctx, ready); err != nil { - slog.Error("validator exited with an error", "error", err) - os.Exit(1) - } + cobra.CheckErr(validator.Create(createInfo, &validatorService)) + validatorService.CreateDefaultHandlers("/" + validatorService.Name) + cobra.CheckErr(validatorService.Serve()) } diff --git a/go.mod b/go.mod index 3a10e726f..41d9fa2ef 100644 --- a/go.mod +++ b/go.mod @@ -16,8 +16,11 @@ require ( github.com/aws/aws-sdk-go-v2 v1.32.2 github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/service/kms v1.37.2 + github.com/davecgh/go-spew v1.1.1 github.com/deepmap/oapi-codegen/v2 v2.1.0 github.com/golang-migrate/migrate/v4 v4.18.1 + github.com/jackc/pgconn v1.14.3 + github.com/jackc/pgx v3.6.2+incompatible github.com/jackc/pgx/v5 v5.7.1 github.com/lmittmann/tint v1.0.5 github.com/mattn/go-isatty v0.0.20 @@ -43,12 +46,12 @@ require ( github.com/aws/smithy-go v1.22.0 // indirect github.com/bits-and-blooms/bitset v1.14.3 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/cockroachdb/apd v1.1.0 // indirect github.com/consensys/bavard v0.1.22 // indirect github.com/consensys/gnark-crypto v0.14.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/ethereum/c-kzg-4844 v1.0.3 // indirect @@ -58,6 +61,7 @@ require ( github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -65,7 +69,11 @@ require ( github.com/holiman/uint256 v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/yaml v0.2.0 // indirect + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect + github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -78,6 +86,7 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.14.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index 0bec5a875..30d3c2e78 100644 --- a/go.sum +++ b/go.sum @@ -60,6 +60,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +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/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= @@ -135,6 +137,8 @@ github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.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-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -175,10 +179,25 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= +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/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= +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-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/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= +github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= @@ -263,6 +282,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +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/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -275,6 +296,7 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -344,6 +366,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/advancer/advancer.go b/internal/advancer/advancer.go index fa3213705..9e5dea38f 100644 --- a/internal/advancer/advancer.go +++ b/internal/advancer/advancer.go @@ -8,12 +8,18 @@ import ( "errors" "fmt" "log/slog" + "net/http" "time" "github.com/cartesi/rollups-node/internal/advancer/machines" + "github.com/cartesi/rollups-node/internal/config" + + "github.com/cartesi/rollups-node/internal/inspect" . "github.com/cartesi/rollups-node/internal/model" "github.com/cartesi/rollups-node/internal/nodemachine" - "github.com/cartesi/rollups-node/internal/services/poller" + "github.com/cartesi/rollups-node/internal/repository" + "github.com/cartesi/rollups-node/pkg/rollupsmachine/cartesimachine" + "github.com/cartesi/rollups-node/pkg/service" ) var ( @@ -24,13 +30,31 @@ var ( ErrNoInputs = errors.New("no inputs") ) +type IAdvancerRepository interface { + // Only needs Id, Index, and RawData fields from the retrieved Inputs. + GetUnprocessedInputs(_ context.Context, apps []Address) (map[Address][]*Input, error) + StoreAdvanceResult(context.Context, *Input, *nodemachine.AdvanceResult) error + UpdateClosedEpochs(_ context.Context, app Address) error +} + +type IAdvancerMachines interface { + GetAdvanceMachine(app Address) (machines.AdvanceMachine, bool) + UpdateMachines(ctx context.Context) error + Apps() []Address +} + type Advancer struct { - machines Machines - repository Repository + repository IAdvancerRepository + machines IAdvancerMachines } -// New instantiates a new Advancer. -func New(machines Machines, repository Repository) (*Advancer, error) { +type Service struct { + service.Service + Advancer + inspector *inspect.Inspector +} + +func New(machines IAdvancerMachines, repository IAdvancerRepository) (*Advancer, error) { if machines == nil { return nil, ErrInvalidMachines } @@ -40,9 +64,80 @@ func New(machines Machines, repository Repository) (*Advancer, error) { return &Advancer{machines: machines, repository: repository}, nil } -// Poller instantiates a new poller.Poller using the Advancer. -func (advancer *Advancer) Poller(pollingInterval time.Duration) (*poller.Poller, error) { - return poller.New("advancer", advancer, pollingInterval) +type CreateInfo struct { + service.CreateInfo + AdvancerPollingInterval time.Duration + PostgresEndpoint config.Redacted[string] + PostgresSslMode bool + Repository *repository.Database + HttpAddress string + HttpPort int + MachineServerVerbosity config.Redacted[cartesimachine.ServerVerbosity] + Machines *machines.Machines +} + +func (c *CreateInfo) LoadEnv() { + c.PostgresEndpoint.Value = config.GetPostgresEndpoint() + c.PollInterval = config.GetAdvancerPollingInterval() + c.HttpAddress = config.GetHttpAddress() + c.HttpPort = config.GetHttpPort() + c.MachineServerVerbosity.Value = + cartesimachine.ServerVerbosity(config.GetMachineServerVerbosity()) + c.LogLevel = service.LogLevel(config.GetLogLevel()) +} + +func Create(c *CreateInfo, s *Service) error { + err := service.Create(&c.CreateInfo, &s.Service) + if err != nil { + return err + } + + if c.Repository == nil { + c.Repository, err = repository.Connect(s.Context, c.PostgresEndpoint.Value) + if err != nil { + return err + } + } + s.repository = c.Repository + + if c.Machines == nil { + c.Machines, err = machines.Load(s.Context, c.Repository, c.MachineServerVerbosity.Value) + if err != nil { + return err + } + } + s.machines = c.Machines + + if s.Service.ServeMux == nil { + if c.CreateInfo.ServeMux == nil { + c.ServeMux = http.NewServeMux() + } + } + s.Service.ServeMux.Handle("/inspect/{dapp}", http.Handler(s.inspector)) + s.Service.ServeMux.Handle("/inspect/{dapp}/{payload}", http.Handler(s.inspector)) + + return nil +} + +func (s *Service) Alive() bool { return true } +func (s *Service) Ready() bool { return true } +func (s *Service) Reload() []error { return nil } +func (s *Service) Tick() []error { + if err := s.Step(s.Context); err != nil { + return []error{err} + } + return []error{} +} +func (s *Service) Stop(b bool) []error { + return nil +} + +func (s *Service) Start(context context.Context, ready chan<- struct{}) error { + ready <- struct{}{} + return s.Serve() +} +func (v *Service) String() string { + return v.Name } // Step steps the Advancer for one processing cycle. @@ -76,7 +171,7 @@ func (advancer *Advancer) Step(ctx context.Context) error { // Updates the status of the epochs. for _, app := range apps { - err := advancer.repository.UpdateEpochs(ctx, app) + err := advancer.repository.UpdateClosedEpochs(ctx, app) if err != nil { return err } @@ -118,23 +213,3 @@ func (advancer *Advancer) process(ctx context.Context, app Address, inputs []*In return nil } -// ------------------------------------------------------------------------------------------------ - -type Repository interface { - // Only needs Id, Index, and RawData fields from the retrieved Inputs. - GetUnprocessedInputs(_ context.Context, apps []Address) (map[Address][]*Input, error) - - StoreAdvanceResult(context.Context, *Input, *nodemachine.AdvanceResult) error - - UpdateEpochs(_ context.Context, app Address) error -} - -type Machines interface { - GetAdvanceMachine(app Address) (machines.AdvanceMachine, bool) - UpdateMachines(ctx context.Context) error - Apps() []Address -} - -type Machine interface { - Advance(_ context.Context, input []byte, index uint64) (*nodemachine.AdvanceResult, error) -} diff --git a/internal/advancer/advancer_test.go b/internal/advancer/advancer_test.go index f86433264..5a863da84 100644 --- a/internal/advancer/advancer_test.go +++ b/internal/advancer/advancer_test.go @@ -30,7 +30,7 @@ func (s *AdvancerSuite) TestNew() { require := s.Require() machines := newMockMachines() machines.Map[randomAddress()] = &MockMachine{} - var repository Repository = &MockRepository{} + var repository IAdvancerRepository = &MockRepository{} advancer, err := New(machines, repository) require.NotNil(advancer) require.Nil(err) @@ -38,8 +38,8 @@ func (s *AdvancerSuite) TestNew() { s.Run("InvalidMachines", func() { require := s.Require() - var machines Machines = nil - var repository Repository = &MockRepository{} + var machines IAdvancerMachines = nil + var repository IAdvancerRepository = &MockRepository{} advancer, err := New(machines, repository) require.Nil(advancer) require.Error(err) @@ -50,7 +50,7 @@ func (s *AdvancerSuite) TestNew() { require := s.Require() machines := newMockMachines() machines.Map[randomAddress()] = &MockMachine{} - var repository Repository = nil + var repository IAdvancerRepository = nil advancer, err := New(machines, repository) require.Nil(advancer) require.Error(err) @@ -105,12 +105,15 @@ func (s *AdvancerSuite) TestRun() { } func (s *AdvancerSuite) TestProcess() { - setup := func() (Machines, *MockRepository, *Advancer, Address) { + setup := func() (IAdvancerMachines, *MockRepository, *Advancer, Address) { app := randomAddress() machines := newMockMachines() machines.Map[app] = &MockMachine{} repository := &MockRepository{} - advancer := &Advancer{machines, repository} + advancer := &Advancer{ + machines: machines, + repository: repository, + } return machines, repository, advancer, app } @@ -261,7 +264,7 @@ func (mock *MockRepository) StoreAdvanceResult( return mock.StoreAdvanceError } -func (mock *MockRepository) UpdateEpochs(_ context.Context, _ Address) error { +func (mock *MockRepository) UpdateClosedEpochs(_ context.Context, _ Address) error { return mock.UpdateEpochsError } diff --git a/internal/advancer/config/config.go b/internal/advancer/config/config.go deleted file mode 100644 index 91df55d22..000000000 --- a/internal/advancer/config/config.go +++ /dev/null @@ -1,34 +0,0 @@ -// (c) Cartesi and individual authors (see AUTHORS) -// SPDX-License-Identifier: Apache-2.0 (see LICENSE) - -// The config package manages the node configuration, which comes from environment variables. -// The sub-package generate specifies these environment variables. -package config - -import ( - . "github.com/cartesi/rollups-node/internal/config" - "github.com/cartesi/rollups-node/pkg/rollupsmachine/cartesimachine" -) - -type AdvancerConfig struct { - LogLevel LogLevel - LogPrettyEnabled bool - PostgresEndpoint Redacted[string] - PostgresSslMode bool - AdvancerPollingInterval Duration - HttpAddress string - HttpPort int - MachineServerVerbosity cartesimachine.ServerVerbosity -} - -func GetAdvancerConfig() AdvancerConfig { - return AdvancerConfig{ - LogLevel: GetLogLevel(), - LogPrettyEnabled: GetLogPrettyEnabled(), - HttpAddress: GetHttpAddress(), - HttpPort: GetHttpPort(), - PostgresEndpoint: Redacted[string]{Value: GetPostgresEndpoint()}, - AdvancerPollingInterval: GetAdvancerPollingInterval(), - MachineServerVerbosity: cartesimachine.ServerVerbosity(GetMachineServerVerbosity()), - } -} diff --git a/internal/advancer/machines/machines_test.go b/internal/advancer/machines/machines_test.go new file mode 100644 index 000000000..bb35c1c56 --- /dev/null +++ b/internal/advancer/machines/machines_test.go @@ -0,0 +1,11 @@ +package machines + +import ( + "github.com/stretchr/testify/mock" +) + +type machinesMock struct { + mock.Mock + Machines +} + diff --git a/internal/advancer/service/service.go b/internal/advancer/service/service.go deleted file mode 100644 index ff584e0fc..000000000 --- a/internal/advancer/service/service.go +++ /dev/null @@ -1,77 +0,0 @@ -// (c) Cartesi and individual authors (see AUTHORS) -// SPDX-License-Identifier: Apache-2.0 (see LICENSE) - -package service - -import ( - "context" - "fmt" - "net/http" - "time" - - "github.com/cartesi/rollups-node/internal/advancer" - "github.com/cartesi/rollups-node/internal/advancer/machines" - "github.com/cartesi/rollups-node/internal/inspect" - "github.com/cartesi/rollups-node/internal/repository" - "github.com/cartesi/rollups-node/pkg/rollupsmachine/cartesimachine" -) - -type AdvancerService struct { - database *repository.Database - serveMux *http.ServeMux - AdvancerPollingInterval time.Duration - MachineServerVerbosity cartesimachine.ServerVerbosity -} - -func NewAdvancerService( - database *repository.Database, - serveMux *http.ServeMux, - pollingInterval time.Duration, - machineServerVerbosity cartesimachine.ServerVerbosity, -) *AdvancerService { - return &AdvancerService{ - database: database, - serveMux: serveMux, - AdvancerPollingInterval: pollingInterval, - MachineServerVerbosity: machineServerVerbosity, - } -} - -func (s *AdvancerService) Start( - ctx context.Context, - ready chan<- struct{}, -) error { - - repo := &repository.MachineRepository{Database: s.database} - - machines, err := machines.Load(ctx, repo, s.MachineServerVerbosity) - if err != nil { - return fmt.Errorf("failed to load the machines: %w", err) - } - defer machines.Close() - - advancer, err := advancer.New(machines, repo) - if err != nil { - return fmt.Errorf("failed to create the advancer: %w", err) - } - - inspector, err := inspect.New(machines) - if err != nil { - return fmt.Errorf("failed to create the inspector: %w", err) - } - - s.serveMux.Handle("/inspect/{dapp}", http.Handler(inspector)) - s.serveMux.Handle("/inspect/{dapp}/{payload}", http.Handler(inspector)) - - poller, err := advancer.Poller(s.AdvancerPollingInterval) - if err != nil { - return fmt.Errorf("failed to create the advancer service: %w", err) - } - - ready <- struct{}{} - return poller.Start(ctx) -} - -func (s *AdvancerService) String() string { - return "advancer" -} diff --git a/internal/evmreader/retrypolicy/contractfactory.go b/internal/evmreader/contractfactory.go similarity index 75% rename from internal/evmreader/retrypolicy/contractfactory.go rename to internal/evmreader/contractfactory.go index 3b399126e..1b7017c96 100644 --- a/internal/evmreader/retrypolicy/contractfactory.go +++ b/internal/evmreader/contractfactory.go @@ -1,11 +1,10 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package retrypolicy +package evmreader import ( "time" - "github.com/cartesi/rollups-node/internal/evmreader" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" ) @@ -16,7 +15,7 @@ type EvmReaderContractFactory struct { maxRetries uint64 maxDelay time.Duration ethClient *ethclient.Client - iConsensusCache map[common.Address]evmreader.ConsensusContract + iConsensusCache map[common.Address]ConsensusContract } func NewEvmReaderContractFactory( @@ -29,17 +28,17 @@ func NewEvmReaderContractFactory( ethClient: ethClient, maxRetries: maxRetries, maxDelay: maxDelay, - iConsensusCache: make(map[common.Address]evmreader.ConsensusContract), + iConsensusCache: make(map[common.Address]ConsensusContract), } } func (f *EvmReaderContractFactory) NewApplication( address common.Address, -) (evmreader.ApplicationContract, error) { +) (ApplicationContract, error) { // Building a contract does not fail due to network errors. // No need to retry this operation - applicationContract, err := evmreader.NewApplicationContractAdapter(address, f.ethClient) + applicationContract, err := NewApplicationContractAdapter(address, f.ethClient) if err != nil { return nil, err } @@ -50,13 +49,13 @@ func (f *EvmReaderContractFactory) NewApplication( func (f *EvmReaderContractFactory) NewIConsensus( address common.Address, -) (evmreader.ConsensusContract, error) { +) (ConsensusContract, error) { delegator, ok := f.iConsensusCache[address] if !ok { // Building a contract does not fail due to network errors. // No need to retry this operation - consensus, err := evmreader.NewConsensusContractAdapter(address, f.ethClient) + consensus, err := NewConsensusContractAdapter(address, f.ethClient) if err != nil { return nil, err } diff --git a/internal/evmreader/evmreader.go b/internal/evmreader/evmreader.go index 5d3d633ea..72fc9d5a7 100644 --- a/internal/evmreader/evmreader.go +++ b/internal/evmreader/evmreader.go @@ -9,17 +9,159 @@ import ( "fmt" "log/slog" "math/big" + "time" + "github.com/cartesi/rollups-node/internal/config" + "github.com/cartesi/rollups-node/internal/model" . "github.com/cartesi/rollups-node/internal/model" + "github.com/cartesi/rollups-node/internal/repository" appcontract "github.com/cartesi/rollups-node/pkg/contracts/iapplication" "github.com/cartesi/rollups-node/pkg/contracts/iconsensus" "github.com/cartesi/rollups-node/pkg/contracts/iinputbox" + "github.com/cartesi/rollups-node/pkg/service" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" + "github.com/jackc/pgx/v5" ) +type CreateInfo struct { + service.CreateInfo + + model.EvmReaderPersistentConfig + + DefaultBlockString string + PostgresEndpoint config.Redacted[string] + BlockchainHttpEndpoint config.Redacted[string] + BlockchainWsEndpoint config.Redacted[string] + Database *repository.Database + MaxRetries uint64 + MaxDelay time.Duration +} + +type Service struct { + service.Service + reader EvmReader +} + +func (c *CreateInfo) LoadEnv() { + c.BlockchainHttpEndpoint.Value = config.GetBlockchainHttpEndpoint() + c.BlockchainWsEndpoint.Value = config.GetBlockchainWsEndpoint() + c.MaxDelay = config.GetEvmReaderRetryPolicyMaxDelay() + c.MaxRetries = config.GetEvmReaderRetryPolicyMaxRetries() + c.PostgresEndpoint.Value = config.GetPostgresEndpoint() + + // persistent + c.DefaultBlock = config.GetEvmReaderDefaultBlock() + c.InputBoxDeploymentBlock = uint64(config.GetContractsInputBoxDeploymentBlockNumber()) + c.InputBoxAddress = common.HexToAddress(config.GetContractsInputBoxAddress()) + c.ChainId = config.GetBlockchainId() +} + +func Create(c *CreateInfo, s *Service) error { + var err error + + err = service.Create(&c.CreateInfo, &s.Service) + if err != nil { + return err + } + + c.DefaultBlock, err = config.ToDefaultBlockFromString(c.DefaultBlockString) + if err != nil { + return err + } + + client, err := ethclient.DialContext(s.Context, c.BlockchainHttpEndpoint.Value) + if err != nil { + return err + } + + wsClient, err := ethclient.DialContext(s.Context, c.BlockchainWsEndpoint.Value) + if err != nil { + return err + } + + if c.Database == nil { + c.Database, err = repository.Connect(s.Context, c.PostgresEndpoint.Value) + if err != nil { + return err + } + } + + err = s.SetupPersistentConfig(s.Context, c.Database, &c.EvmReaderPersistentConfig) + if err != nil { + return err + } + + inputSource, err := NewInputSourceAdapter(c.InputBoxAddress, client) + if err != nil { + return err + } + + contractFactory := NewEvmReaderContractFactory(client, c.MaxRetries, c.MaxDelay) + + s.reader = NewEvmReader( + NewEhtClientWithRetryPolicy(client, c.MaxRetries, c.MaxDelay), + NewEthWsClientWithRetryPolicy(wsClient, c.MaxRetries, c.MaxDelay), + NewInputSourceWithRetryPolicy(inputSource, c.MaxRetries, c.MaxDelay), + c.Database, + c.InputBoxDeploymentBlock, + c.DefaultBlock, + contractFactory, + ) + return nil +} + +func (s *Service) Alive() bool { + return true +} + +func (s *Service) Ready() bool { + return true +} + +func (s *Service) Reload() []error { + return nil +} + +func (s *Service) Stop(bool) []error { + return nil +} + +func (s *Service) Tick() []error { + return []error{} +} + +func (s *Service) Start(context context.Context, ready chan<- struct{}) error { + go s.reader.Run(s.Context, ready) + return s.Serve() +} +func (s *Service) String() string { + return s.Name +} + +func (me *Service) SetupPersistentConfig( + ctx context.Context, + database *repository.Database, + c *model.EvmReaderPersistentConfig, +) error { + err := database.SelectEvmReaderConfig(ctx, c) + if err == pgx.ErrNoRows { + _, err = database.InsertEvmReaderConfig(ctx, c) + if err != nil { + return err + } + } else if err == nil { + me.Logger.Info("Node was already configured. Using previous persistent config", "config", c) + } else { + me.Logger.Error("Could not retrieve persistent config from Database. %w", "error", err) + } + return err +} + // Interface for Input reading type InputSource interface { // Wrapper for FilterInputAdded(), which is automatically generated @@ -36,7 +178,7 @@ type EvmReaderRepository interface { ) (epochIndexIdMap map[uint64]uint64, epochIndexInputIdsMap map[uint64][]uint64, err error) GetAllRunningApplications(ctx context.Context) ([]Application, error) - GetNodeConfig(ctx context.Context) (*NodePersistentConfig, error) + SelectEvmReaderConfig(context.Context, *model.EvmReaderPersistentConfig) error GetEpoch(ctx context.Context, indexKey uint64, appAddressKey Address) (*Epoch, error) GetPreviousEpochsWithOpenClaims( ctx context.Context, diff --git a/internal/evmreader/evmreader_test.go b/internal/evmreader/evmreader_test.go index a80919282..7a4a80753 100644 --- a/internal/evmreader/evmreader_test.go +++ b/internal/evmreader/evmreader_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/cartesi/rollups-node/internal/model" . "github.com/cartesi/rollups-node/internal/model" appcontract "github.com/cartesi/rollups-node/pkg/contracts/iapplication" "github.com/cartesi/rollups-node/pkg/contracts/iconsensus" @@ -590,11 +591,12 @@ func (m *MockRepository) GetAllRunningApplications( return args.Get(0).([]Application), args.Error(1) } -func (m *MockRepository) GetNodeConfig( +func (m *MockRepository) SelectEvmReaderConfig( ctx context.Context, -) (*NodePersistentConfig, error) { - args := m.Called(ctx) - return args.Get(0).(*NodePersistentConfig), args.Error(1) + out *model.EvmReaderPersistentConfig, +) error { + args := m.Called(ctx, out) + return args.Error(0) } func (m *MockRepository) GetEpoch( diff --git a/internal/evmreader/retrypolicy/retrypolicy_application_delegator.go b/internal/evmreader/retrypolicy_application_delegator.go similarity index 88% rename from internal/evmreader/retrypolicy/retrypolicy_application_delegator.go rename to internal/evmreader/retrypolicy_application_delegator.go index b3eabd738..6ba57bb75 100644 --- a/internal/evmreader/retrypolicy/retrypolicy_application_delegator.go +++ b/internal/evmreader/retrypolicy_application_delegator.go @@ -1,12 +1,11 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package retrypolicy +package evmreader import ( "time" - "github.com/cartesi/rollups-node/internal/evmreader" "github.com/cartesi/rollups-node/internal/services/retry" "github.com/cartesi/rollups-node/pkg/contracts/iapplication" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -14,13 +13,13 @@ import ( ) type ApplicationRetryPolicyDelegator struct { - delegate evmreader.ApplicationContract + delegate ApplicationContract maxRetries uint64 delayBetweenCalls time.Duration } func NewApplicationWithRetryPolicy( - delegate evmreader.ApplicationContract, + delegate ApplicationContract, maxRetries uint64, delayBetweenCalls time.Duration, ) *ApplicationRetryPolicyDelegator { diff --git a/internal/evmreader/retrypolicy/retrypolicy_consensus_delegator.go b/internal/evmreader/retrypolicy_consensus_delegator.go similarity index 92% rename from internal/evmreader/retrypolicy/retrypolicy_consensus_delegator.go rename to internal/evmreader/retrypolicy_consensus_delegator.go index 82e1e28db..429f1a885 100644 --- a/internal/evmreader/retrypolicy/retrypolicy_consensus_delegator.go +++ b/internal/evmreader/retrypolicy_consensus_delegator.go @@ -1,13 +1,12 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package retrypolicy +package evmreader import ( "math/big" "time" - "github.com/cartesi/rollups-node/internal/evmreader" "github.com/cartesi/rollups-node/internal/services/retry" "github.com/cartesi/rollups-node/pkg/contracts/iconsensus" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -18,13 +17,13 @@ import ( // calls GetEpochLength with the retry // policy defined by util.RetryFunction type ConsensusRetryPolicyDelegator struct { - delegate evmreader.ConsensusContract + delegate ConsensusContract maxRetries uint64 delayBetweenCalls time.Duration } func NewConsensusWithRetryPolicy( - delegate evmreader.ConsensusContract, + delegate ConsensusContract, maxRetries uint64, delayBetweenCalls time.Duration, ) *ConsensusRetryPolicyDelegator { diff --git a/internal/evmreader/retrypolicy/retrypolicy_ethclient_delegator.go b/internal/evmreader/retrypolicy_ethclient_delegator.go similarity index 90% rename from internal/evmreader/retrypolicy/retrypolicy_ethclient_delegator.go rename to internal/evmreader/retrypolicy_ethclient_delegator.go index d4cb11a2d..f4ecf9a66 100644 --- a/internal/evmreader/retrypolicy/retrypolicy_ethclient_delegator.go +++ b/internal/evmreader/retrypolicy_ethclient_delegator.go @@ -1,14 +1,13 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package retrypolicy +package evmreader import ( "context" "math/big" "time" - "github.com/cartesi/rollups-node/internal/evmreader" "github.com/cartesi/rollups-node/internal/services/retry" "github.com/ethereum/go-ethereum/core/types" ) @@ -17,13 +16,13 @@ import ( // calls HeaderByNumber with the retry // policy defined by util.RetryFunction type EthClientRetryPolicyDelegator struct { - delegate evmreader.EthClient + delegate EthClient maxRetries uint64 delayBetweenCalls time.Duration } func NewEhtClientWithRetryPolicy( - delegate evmreader.EthClient, + delegate EthClient, maxRetries uint64, delayBetweenCalls time.Duration, ) *EthClientRetryPolicyDelegator { diff --git a/internal/evmreader/retrypolicy/retrypolicy_ethwsclient_delegator.go b/internal/evmreader/retrypolicy_ethwsclient_delegator.go similarity index 89% rename from internal/evmreader/retrypolicy/retrypolicy_ethwsclient_delegator.go rename to internal/evmreader/retrypolicy_ethwsclient_delegator.go index 154a35998..a480f729f 100644 --- a/internal/evmreader/retrypolicy/retrypolicy_ethwsclient_delegator.go +++ b/internal/evmreader/retrypolicy_ethwsclient_delegator.go @@ -1,26 +1,25 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package retrypolicy +package evmreader import ( "context" "time" - "github.com/cartesi/rollups-node/internal/evmreader" "github.com/cartesi/rollups-node/internal/services/retry" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/core/types" ) type EthWsClientRetryPolicyDelegator struct { - delegate evmreader.EthWsClient + delegate EthWsClient maxRetries uint64 delayBetweenCalls time.Duration } func NewEthWsClientWithRetryPolicy( - delegate evmreader.EthWsClient, + delegate EthWsClient, maxRetries uint64, delayBetweenCalls time.Duration, ) *EthWsClientRetryPolicyDelegator { diff --git a/internal/evmreader/retrypolicy/retrypolicy_inputsource_delegator.go b/internal/evmreader/retrypolicy_inputsource_delegator.go similarity index 91% rename from internal/evmreader/retrypolicy/retrypolicy_inputsource_delegator.go rename to internal/evmreader/retrypolicy_inputsource_delegator.go index a36996b60..b6156bcda 100644 --- a/internal/evmreader/retrypolicy/retrypolicy_inputsource_delegator.go +++ b/internal/evmreader/retrypolicy_inputsource_delegator.go @@ -1,13 +1,12 @@ // (c) Cartesi and individual authors (see AUTHORS) // SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package retrypolicy +package evmreader import ( "math/big" "time" - "github.com/cartesi/rollups-node/internal/evmreader" "github.com/cartesi/rollups-node/internal/services/retry" "github.com/cartesi/rollups-node/pkg/contracts/iinputbox" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -15,13 +14,13 @@ import ( ) type InputSourceWithRetryPolicyDelegator struct { - delegate evmreader.InputSource + delegate InputSource maxRetries uint64 delay time.Duration } func NewInputSourceWithRetryPolicy( - delegate evmreader.InputSource, + delegate InputSource, maxRetries uint64, delay time.Duration, ) *InputSourceWithRetryPolicyDelegator { diff --git a/internal/evmreader/service/evmreader_service.go b/internal/evmreader/service/evmreader_service.go deleted file mode 100644 index f97de5dc3..000000000 --- a/internal/evmreader/service/evmreader_service.go +++ /dev/null @@ -1,85 +0,0 @@ -// (c) Cartesi and individual authors (see AUTHORS) -// SPDX-License-Identifier: Apache-2.0 (see LICENSE) - -package service - -import ( - "context" - "time" - - "github.com/cartesi/rollups-node/internal/evmreader" - "github.com/cartesi/rollups-node/internal/evmreader/retrypolicy" - "github.com/cartesi/rollups-node/internal/repository" - "github.com/ethereum/go-ethereum/ethclient" -) - -// Service to manage InputReader lifecycle -type EvmReaderService struct { - blockchainHttpEndpoint string - blockchainWsEndpoint string - database *repository.Database - maxRetries uint64 - maxDelay time.Duration -} - -func NewEvmReaderService( - blockchainHttpEndpoint string, - blockchainWsEndpoint string, - database *repository.Database, - maxRetries uint64, - maxDelay time.Duration, -) *EvmReaderService { - return &EvmReaderService{ - blockchainHttpEndpoint: blockchainHttpEndpoint, - blockchainWsEndpoint: blockchainWsEndpoint, - database: database, - maxRetries: maxRetries, - maxDelay: maxDelay, - } -} - -func (s *EvmReaderService) Start( - ctx context.Context, - ready chan<- struct{}, -) error { - - client, err := ethclient.DialContext(ctx, s.blockchainHttpEndpoint) - if err != nil { - return err - } - defer client.Close() - - wsClient, err := ethclient.DialContext(ctx, s.blockchainWsEndpoint) - if err != nil { - return err - } - defer wsClient.Close() - - config, err := s.database.GetNodeConfig(ctx) - if err != nil { - return err - } - - inputSource, err := evmreader.NewInputSourceAdapter(config.InputBoxAddress, client) - if err != nil { - return err - } - - contractFactory := retrypolicy.NewEvmReaderContractFactory(client, s.maxRetries, s.maxDelay) - - reader := evmreader.NewEvmReader( - retrypolicy.NewEhtClientWithRetryPolicy(client, s.maxRetries, s.maxDelay), - retrypolicy.NewEthWsClientWithRetryPolicy(wsClient, s.maxRetries, s.maxDelay), - retrypolicy.NewInputSourceWithRetryPolicy(inputSource, s.maxRetries, s.maxDelay), - s.database, - config.InputBoxDeploymentBlock, - config.DefaultBlock, - contractFactory, - ) - - return reader.Run(ctx, ready) -} - -func (s *EvmReaderService) String() string { - return "evmreader" -} diff --git a/internal/inspect/inspect.go b/internal/inspect/inspect.go index 0cd6c6857..bef157b24 100644 --- a/internal/inspect/inspect.go +++ b/internal/inspect/inspect.go @@ -26,7 +26,7 @@ var ( ) type Inspector struct { - machines Machines + IInspectMachines } type ReportResponse struct { @@ -40,15 +40,6 @@ type InspectResponse struct { ProcessedInputs uint64 `json:"processed_input_count"` } -// New instantiates a new Inspector. -func New(machines Machines) (*Inspector, error) { - if machines == nil { - return nil, ErrInvalidMachines - } - - return &Inspector{machines: machines}, nil -} - func (inspect *Inspector) ServeHTTP(w http.ResponseWriter, r *http.Request) { var ( dapp Address @@ -146,7 +137,7 @@ func (inspect *Inspector) process( app Address, query []byte) (*nodemachine.InspectResult, error) { // Asserts that the app has an associated machine. - machine, exists := inspect.machines.GetInspectMachine(app) + machine, exists := inspect.GetInspectMachine(app) if !exists { return nil, fmt.Errorf("%w %s", ErrNoApp, app.String()) } @@ -161,10 +152,10 @@ func (inspect *Inspector) process( // ------------------------------------------------------------------------------------------------ -type Machines interface { +type IInspectMachines interface { GetInspectMachine(app Address) (machines.InspectMachine, bool) } -type Machine interface { +type IInspectMachine interface { Inspect(_ context.Context, query []byte) (*nodemachine.InspectResult, error) } diff --git a/internal/inspect/inspect_test.go b/internal/inspect/inspect_test.go index 8f1a84201..be5e6f9e8 100644 --- a/internal/inspect/inspect_test.go +++ b/internal/inspect/inspect_test.go @@ -45,26 +45,6 @@ func (s *InspectSuite) SetupTest() { s.ServiceAddr = fmt.Sprintf("127.0.0.1:%v", s.ServicePort) } -func (s *InspectSuite) TestNew() { - s.Run("Ok", func() { - require := s.Require() - machines := newMockMachines() - machines.Map[randomAddress()] = &MockMachine{} - inspect, err := New(machines) - require.NotNil(inspect) - require.Nil(err) - }) - - s.Run("InvalidMachines", func() { - require := s.Require() - var machines Machines = nil - inspect, err := New(machines) - require.Nil(inspect) - require.Error(err) - require.Equal(ErrInvalidMachines, err) - }) -} - func (s *InspectSuite) TestGetOk() { inspect, app, payload := s.setup() diff --git a/internal/model/models.go b/internal/model/models.go index f96979b21..8df78059c 100644 --- a/internal/model/models.go +++ b/internal/model/models.go @@ -56,7 +56,7 @@ const ( EpochStatusClaimRejected EpochStatus = "CLAIM_REJECTED" ) -type NodePersistentConfig struct { +type EvmReaderPersistentConfig struct { DefaultBlock DefaultBlock InputBoxDeploymentBlock uint64 InputBoxAddress Address diff --git a/internal/node/services.go b/internal/node/services.go index f0efc756d..65e154fae 100644 --- a/internal/node/services.go +++ b/internal/node/services.go @@ -5,16 +5,15 @@ package node import ( "fmt" - "log/slog" "net/http" - advancerservice "github.com/cartesi/rollups-node/internal/advancer/service" + advancerservice "github.com/cartesi/rollups-node/internal/advancer" claimerservice "github.com/cartesi/rollups-node/internal/claimer" "github.com/cartesi/rollups-node/internal/config" - evmreaderservice "github.com/cartesi/rollups-node/internal/evmreader/service" + readerservice "github.com/cartesi/rollups-node/internal/evmreader" "github.com/cartesi/rollups-node/internal/repository" "github.com/cartesi/rollups-node/internal/services" - "github.com/cartesi/rollups-node/internal/validator" + validatorservice "github.com/cartesi/rollups-node/internal/validator" "github.com/cartesi/rollups-node/pkg/service" ) @@ -62,30 +61,69 @@ func newHttpService(c config.NodeConfig, serveMux *http.ServeMux) services.Servi } func newEvmReaderService(c config.NodeConfig, database *repository.Database) services.Service { - return evmreaderservice.NewEvmReaderService( - c.BlockchainHttpEndpoint.Value, - c.BlockchainWsEndpoint.Value, - database, - c.EvmReaderRetryPolicyMaxRetries, - c.EvmReaderRetryPolicyMaxDelay, - ) + readerService := readerservice.Service{} + createInfo := readerservice.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "reader", + Impl: &readerService, + ProcOwner: true, // TODO: Remove this after updating supervisor + LogLevel: service.LogLevel(c.LogLevel), + }, + Database: database, + } + + err := readerservice.Create(&createInfo, &readerService) + if err != nil { + readerService.Logger.Error("Fatal", + "service", readerService.Name, + "error", err) + } + return &readerService } func newAdvancerService(c config.NodeConfig, database *repository.Database, serveMux *http.ServeMux) services.Service { - return advancerservice.NewAdvancerService( - database, - serveMux, - c.AdvancerPollingInterval, - c.MachineServerVerbosity, - ) + advancerService := advancerservice.Service{} + createInfo := advancerservice.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "advancer", + PollInterval: c.AdvancerPollingInterval, + Impl: &advancerService, + ProcOwner: true, // TODO: Remove this after updating supervisor + LogLevel: service.LogLevel(c.LogLevel), + ServeMux: serveMux, + }, + Repository: database, + } + + err := advancerservice.Create(&createInfo, &advancerService) + if err != nil { + advancerService.Logger.Error("Fatal", + "service", advancerService.Name, + "error", err) + } + return &advancerService } func newValidatorService(c config.NodeConfig, database *repository.Database) services.Service { - return validator.NewValidatorService( - database, - uint64(c.ContractsInputBoxDeploymentBlockNumber), - c.ValidatorPollingInterval, - ) + validatorService := validatorservice.Service{} + createInfo := validatorservice.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "validator", + PollInterval: c.ValidatorPollingInterval, + Impl: &validatorService, + ProcOwner: true, // TODO: Remove this after updating supervisor + LogLevel: service.LogLevel(c.LogLevel), + }, + Repository: database, + } + + err := validatorservice.Create(createInfo, &validatorService) + if err != nil { + validatorService.Logger.Error("Fatal", + "service", validatorService.Name, + "error", err) + } + return &validatorService } func newClaimerService(c config.NodeConfig, database *repository.Database) services.Service { @@ -101,12 +139,7 @@ func newClaimerService(c config.NodeConfig, database *repository.Database) servi PollInterval: c.ClaimerPollingInterval, Impl: &claimerService, ProcOwner: true, // TODO: Remove this after updating supervisor - LogLevel: map[slog.Level]string{ // reverse it to string - slog.LevelDebug: "debug", - slog.LevelInfo: "info", - slog.LevelWarn: "warn", - slog.LevelError: "error", - }[c.LogLevel], + LogLevel: service.LogLevel(c.LogLevel), }, } diff --git a/internal/repository/base.go b/internal/repository/base.go index b9106669a..64862861e 100644 --- a/internal/repository/base.go +++ b/internal/repository/base.go @@ -89,38 +89,6 @@ func (pg *Database) Close() { } } -func (pg *Database) InsertNodeConfig( - ctx context.Context, - config *NodePersistentConfig, -) error { - query := ` - INSERT INTO node_config - (default_block, - input_box_deployment_block, - input_box_address, - chain_id) - SELECT - @defaultBlock, - @deploymentBlock, - @inputBoxAddress, - @chainId - WHERE NOT EXISTS (SELECT * FROM node_config)` - - args := pgx.NamedArgs{ - "defaultBlock": config.DefaultBlock, - "deploymentBlock": config.InputBoxDeploymentBlock, - "inputBoxAddress": config.InputBoxAddress, - "chainId": config.ChainId, - } - - _, err := pg.db.Exec(ctx, query, args) - if err != nil { - return fmt.Errorf("%w: %w", ErrInsertRow, err) - } - - return nil -} - func (pg *Database) InsertApplication( ctx context.Context, app *Application, @@ -382,45 +350,6 @@ func (pg *Database) InsertSnapshot( return id, nil } -func (pg *Database) GetNodeConfig( - ctx context.Context, -) (*NodePersistentConfig, error) { - var ( - defaultBlock DefaultBlock - deploymentBlock uint64 - inputBoxAddress Address - chainId uint64 - ) - - query := ` - SELECT - default_block, - input_box_deployment_block, - input_box_address, - chain_id - FROM - node_config` - - err := pg.db.QueryRow(ctx, query).Scan( - &defaultBlock, - &deploymentBlock, - &inputBoxAddress, - &chainId, - ) - if err != nil { - return nil, fmt.Errorf("GetNodeConfig QueryRow failed: %w\n", err) - } - - config := NodePersistentConfig{ - DefaultBlock: defaultBlock, - InputBoxDeploymentBlock: deploymentBlock, - InputBoxAddress: inputBoxAddress, - ChainId: chainId, - } - - return &config, nil -} - func (pg *Database) GetApplication( ctx context.Context, appAddressKey Address, diff --git a/internal/repository/base_test.go b/internal/repository/base_test.go index 40ad67359..5181c1d45 100644 --- a/internal/repository/base_test.go +++ b/internal/repository/base_test.go @@ -46,16 +46,7 @@ func (s *RepositorySuite) TearDownSuite() { } func (s *RepositorySuite) SetupDatabase() { - config := NodePersistentConfig{ - DefaultBlock: DefaultBlockStatusFinalized, - InputBoxDeploymentBlock: 1, - InputBoxAddress: common.HexToAddress("deadbeef"), - ChainId: 1, - } - - err := s.database.InsertNodeConfig(s.ctx, &config) - s.Require().Nil(err) - + var err error app := Application{ ContractAddress: common.HexToAddress("deadbeef"), IConsensusAddress: common.HexToAddress("ffffff"), diff --git a/internal/repository/evmreader.go b/internal/repository/evmreader.go index d9b14c561..c3f35b56d 100644 --- a/internal/repository/evmreader.go +++ b/internal/repository/evmreader.go @@ -10,6 +10,7 @@ import ( . "github.com/cartesi/rollups-node/internal/model" "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" ) var ( @@ -449,3 +450,52 @@ func (pg *Database) UpdateOutputExecutionTransaction( return nil } + +func (pg *Database) SelectEvmReaderConfig( + ctx context.Context, + c *EvmReaderPersistentConfig, +) error { + query := ` + SELECT + default_block, + input_box_deployment_block, + input_box_address, + chain_id + FROM + node_config` + + return pg.db.QueryRow(ctx, query).Scan( + &c.DefaultBlock, + &c.InputBoxDeploymentBlock, + &c.InputBoxAddress, + &c.ChainId, + ) +} + +func (pg *Database) InsertEvmReaderConfig( + ctx context.Context, + c *EvmReaderPersistentConfig, +) (pgconn.CommandTag, error) { + query := ` + INSERT INTO node_config + (default_block, + input_box_deployment_block, + input_box_address, + chain_id) + SELECT + @defaultBlock, + @deploymentBlock, + @inputBoxAddress, + @chainId + WHERE NOT EXISTS (SELECT * FROM node_config)` + + args := pgx.NamedArgs{ + "defaultBlock": c.DefaultBlock, + "deploymentBlock": c.InputBoxDeploymentBlock, + "inputBoxAddress": c.InputBoxAddress, + "chainId": c.ChainId, + } + + return pg.db.Exec(ctx, query, args) +} + diff --git a/internal/repository/machine.go b/internal/repository/machine.go index c001fff36..d55387b03 100644 --- a/internal/repository/machine.go +++ b/internal/repository/machine.go @@ -17,9 +17,7 @@ import ( var ErrAdvancerRepository = errors.New("advancer repository error") -type MachineRepository struct{ *Database } - -func (repo *MachineRepository) GetMachineConfigurations( +func (repo *Database) GetMachineConfigurations( ctx context.Context, ) ([]*MachineConfig, error) { // Query string to fetch application and execution parameters for "running" applications @@ -95,7 +93,7 @@ func (repo *MachineRepository) GetMachineConfigurations( return machineConfigs, nil } -func (repo *MachineRepository) GetProcessedInputs( +func (repo *Database) GetProcessedInputs( ctx context.Context, app Address, index uint64, @@ -132,7 +130,7 @@ func (repo *MachineRepository) GetProcessedInputs( return res, nil } -func (repo *MachineRepository) GetUnprocessedInputs( +func (repo *Database) GetUnprocessedInputs( ctx context.Context, apps []Address, ) (map[Address][]*Input, error) { @@ -171,7 +169,7 @@ func (repo *MachineRepository) GetUnprocessedInputs( return result, nil } -func (repo *MachineRepository) StoreAdvanceResult( +func (repo *Database) StoreAdvanceResult( ctx context.Context, input *Input, res *nodemachine.AdvanceResult, @@ -215,7 +213,7 @@ func (repo *MachineRepository) StoreAdvanceResult( return nil } -func (repo *MachineRepository) UpdateEpochs(ctx context.Context, app Address) error { +func (repo *Database) UpdateClosedEpochs(ctx context.Context, app Address) error { query := ` UPDATE epoch SET status = 'PROCESSED_ALL_INPUTS' @@ -242,7 +240,7 @@ func (repo *MachineRepository) UpdateEpochs(ctx context.Context, app Address) er // ------------------------------------------------------------------------------------------------ -func (_ *MachineRepository) getNextIndex( +func (_ *Database) getNextIndex( ctx context.Context, tx pgx.Tx, tableName string, @@ -263,7 +261,7 @@ func (_ *MachineRepository) getNextIndex( return nextIndex, nil } -func (_ *MachineRepository) insert( +func (_ *Database) insert( ctx context.Context, tx pgx.Tx, tableName string, @@ -298,7 +296,7 @@ func (_ *MachineRepository) insert( return nil } -func (_ *MachineRepository) updateInput( +func (_ *Database) updateInput( ctx context.Context, tx pgx.Tx, inputId uint64, diff --git a/internal/repository/machine_test.go b/internal/repository/machine_test.go index 0034ec20c..90a6897ec 100644 --- a/internal/repository/machine_test.go +++ b/internal/repository/machine_test.go @@ -37,10 +37,8 @@ func TestMachineRepository(t *testing.T) { require.Nil(err) require.Len(apps, 3) - repository := &MachineRepository{Database: database} - // only running apps - res, err := repository.GetMachineConfigurations(ctx) + res, err := database.GetMachineConfigurations(ctx) require.Nil(err) require.Len(res, 2) @@ -92,24 +90,23 @@ func TestMachineRepository(t *testing.T) { app, _, _, err := populate1(database) require.Nil(err) - repository := &MachineRepository{Database: database} - err = repository.UpdateEpochs(ctx, app.ContractAddress) + err = database.UpdateClosedEpochs(ctx, app.ContractAddress) require.Nil(err) - epoch0, err := repository.GetEpoch(ctx, 0, app.ContractAddress) + epoch0, err := database.GetEpoch(ctx, 0, app.ContractAddress) require.Nil(err) require.NotNil(epoch0) - epoch1, err := repository.GetEpoch(ctx, 1, app.ContractAddress) + epoch1, err := database.GetEpoch(ctx, 1, app.ContractAddress) require.Nil(err) require.NotNil(epoch1) - epoch2, err := repository.GetEpoch(ctx, 2, app.ContractAddress) + epoch2, err := database.GetEpoch(ctx, 2, app.ContractAddress) require.Nil(err) require.NotNil(epoch2) - epoch3, err := repository.GetEpoch(ctx, 3, app.ContractAddress) + epoch3, err := database.GetEpoch(ctx, 3, app.ContractAddress) require.Nil(err) require.NotNil(epoch3) diff --git a/internal/services/startup/startup.go b/internal/services/startup/startup.go deleted file mode 100644 index 239b762ac..000000000 --- a/internal/services/startup/startup.go +++ /dev/null @@ -1,76 +0,0 @@ -// (c) Cartesi and individual authors (see AUTHORS) -// SPDX-License-Identifier: Apache-2.0 (see LICENSE) -package startup - -import ( - "context" - "errors" - "fmt" - "log/slog" - "os" - - "github.com/cartesi/rollups-node/internal/config" - "github.com/cartesi/rollups-node/internal/model" - "github.com/cartesi/rollups-node/internal/repository" - "github.com/ethereum/go-ethereum/common" - "github.com/jackc/pgx/v5" - "github.com/lmittmann/tint" - "github.com/mattn/go-isatty" -) - -// Configure the node logs -func ConfigLogs(logLevel slog.Level, logPrettyEnabled bool) { - opts := &tint.Options{ - Level: logLevel, - AddSource: logLevel == slog.LevelDebug, - NoColor: !logPrettyEnabled || !isatty.IsTerminal(os.Stdout.Fd()), - TimeFormat: "2006-01-02T15:04:05.000", // RFC3339 with milliseconds and without timezone - } - handler := tint.NewHandler(os.Stdout, opts) - logger := slog.New(handler) - slog.SetDefault(logger) -} - -// Handles Persistent Config -func SetupNodePersistentConfig( - ctx context.Context, - database *repository.Database, - config config.NodeConfig, -) (*model.NodePersistentConfig, error) { - nodePersistentConfig, err := database.GetNodeConfig(ctx) - if err != nil { - if !errors.Is(err, pgx.ErrNoRows) { - return nil, fmt.Errorf( - "Could not retrieve persistent config from Database. %w", - err, - ) - } - } - - if nodePersistentConfig == nil { - nodePersistentConfig = &model.NodePersistentConfig{ - DefaultBlock: config.EvmReaderDefaultBlock, - InputBoxDeploymentBlock: uint64(config.ContractsInputBoxDeploymentBlockNumber), - InputBoxAddress: common.HexToAddress(config.ContractsInputBoxAddress), - ChainId: config.BlockchainID, - } - slog.Info( - "No persistent config found at the database. Setting it up", - "persistent config", - nodePersistentConfig, - ) - - err = database.InsertNodeConfig(ctx, nodePersistentConfig) - if err != nil { - return nil, fmt.Errorf("Couldn't insert database config. Error : %v", err) - } - } else { - slog.Info( - "Node was already configured. Using previous persistent config", - "persistent config", - nodePersistentConfig, - ) - } - - return nodePersistentConfig, nil -} diff --git a/internal/validator/validator.go b/internal/validator/validator.go index 389a8190b..613db042d 100644 --- a/internal/validator/validator.go +++ b/internal/validator/validator.go @@ -11,11 +11,71 @@ import ( "log/slog" "time" + "github.com/cartesi/rollups-node/internal/config" "github.com/cartesi/rollups-node/internal/merkle" . "github.com/cartesi/rollups-node/internal/model" + "github.com/cartesi/rollups-node/internal/repository" + "github.com/cartesi/rollups-node/pkg/service" "github.com/ethereum/go-ethereum/crypto" ) +type Service struct { + service.Service + repository ValidatorRepository +} + +type CreateInfo struct { + service.CreateInfo + PostgresEndpoint config.Redacted[string] + Repository ValidatorRepository + PollingInterval time.Duration +} + +func (c *CreateInfo) LoadEnv() { + c.PostgresEndpoint.Value = config.GetPostgresEndpoint() + c.PollInterval = config.GetValidatorPollingInterval() + c.LogLevel = service.LogLevel(config.GetLogLevel()) +} + +func Create(ci CreateInfo, s *Service) error { + var err error + + err = service.Create(&ci.CreateInfo, &s.Service) + if err != nil { + return err + } + + if ci.Repository == nil { + ci.Repository, err = repository.Connect(s.Context, ci.PostgresEndpoint.Value) + if err != nil { + return err + } + } + s.repository = ci.Repository + return nil +} + +func (s *Service) Alive() bool { return true } +func (s *Service) Ready() bool { return true } +func (s *Service) Reload() []error { return nil } +func (s *Service) Tick() []error { + if err := s.Run(s.Context); err != nil { + return []error{err} + } + return []error{} +} +func (s *Service) Stop(b bool) []error { + return nil +} + +func (s *Service) Start(context context.Context, ready chan<- struct{}) error { + ready <- struct{}{} + return s.Serve() +} +func (v *Service) String() string { + return v.Name +} + // The maximum height for the Merkle tree of all outputs produced // by an application const MAX_OUTPUT_TREE_HEIGHT = 63 @@ -58,29 +118,11 @@ type ValidatorRepository interface { ) error } -// Validator creates epoch claims and rollups outputs proofs for all running -// applications. -type Validator struct { - repository ValidatorRepository - inputBoxDeploymentBlock uint64 -} - -func NewValidator( - repo ValidatorRepository, - inputBoxDeploymentBlock uint64, -) *Validator { - return &Validator{repo, inputBoxDeploymentBlock} -} - -func (v *Validator) String() string { - return "validator" -} - // Run executes the Validator main logic of producing claims and/or proofs // for processed epochs of all running applications. It is meant to be executed // inside a loop. If an error occurs while processing any epoch, it halts and // returns the error. -func (v *Validator) Run(ctx context.Context) error { +func (v *Service) Run(ctx context.Context) error { apps, err := v.repository.GetAllRunningApplications(ctx) if err != nil { return fmt.Errorf("failed to get running applications. %w", err) @@ -96,7 +138,7 @@ func (v *Validator) Run(ctx context.Context) error { // validateApplication calculates, validates and stores the claim and/or proofs // for each processed epoch of the application. -func (v *Validator) validateApplication(ctx context.Context, app Application) error { +func (v *Service) validateApplication(ctx context.Context, app Application) error { slog.Debug("validator: starting validation", "application", app.ContractAddress) processedEpochs, err := v.repository.GetProcessedEpochs(ctx, app.ContractAddress) if err != nil { @@ -179,7 +221,7 @@ func (v *Validator) validateApplication(ctx context.Context, app Application) er // the claim and the epoch outputs updated with their hash and proofs. In case // the epoch has no outputs, there are no proofs and it returns the pristine // claim for the first epoch or the previous epoch claim otherwise. -func (v *Validator) createClaimAndProofs( +func (v *Service) createClaimAndProofs( ctx context.Context, epoch Epoch, ) (*Hash, []Output, error) { @@ -226,7 +268,7 @@ func (v *Validator) createClaimAndProofs( previousOutputs, err = v.repository.GetOutputsProducedInBlockRange( ctx, epoch.AppAddress, - v.inputBoxDeploymentBlock, + 0, // Current implementation requires all outputs previousEpoch.LastBlock, ) if err != nil { @@ -276,43 +318,3 @@ func (v *Validator) createClaimAndProofs( // if there are no outputs and there is a previous epoch, return its claim return previousEpoch.ClaimHash, nil, nil } - -// ValidatorService extends the Validator utility by executing it with a polling -// strategy. It implements the `services.Service` interface. -type ValidatorService struct { - validator *Validator - pollingInterval time.Duration -} - -func NewValidatorService( - repo ValidatorRepository, - inputBoxDeploymentBlock uint64, - pollingInterval time.Duration, -) *ValidatorService { - service := &ValidatorService{pollingInterval: pollingInterval} - service.validator = NewValidator(repo, inputBoxDeploymentBlock) - return service -} - -func (s *ValidatorService) String() string { - return "validator" -} - -func (s *ValidatorService) Start(ctx context.Context, ready chan<- struct{}) error { - ready <- struct{}{} - - ticker := time.NewTicker(s.pollingInterval) - defer ticker.Stop() - - for { - if err := s.validator.Run(ctx); err != nil { - return err - } - - select { - case <-ctx.Done(): - return ctx.Err() - case <-ticker.C: - } - } -} diff --git a/internal/validator/validator_test.go b/internal/validator/validator_test.go index d3f1985a2..db58109e1 100644 --- a/internal/validator/validator_test.go +++ b/internal/validator/validator_test.go @@ -23,14 +23,16 @@ func TestValidatorSuite(t *testing.T) { } var ( - validator *Validator - repository *MockRepository + validator *Service + repo *Mockrepo dummyEpochs []Epoch ) func (s *ValidatorSuite) SetupSubTest() { - repository = newMockRepository() - validator = NewValidator(repository, 0) + repo = newMockrepo() + validator = &Service{ + repository: repo, + } dummyEpochs = []Epoch{ {Index: 0, FirstBlock: 0, LastBlock: 9}, {Index: 1, FirstBlock: 10, LastBlock: 19}, @@ -40,7 +42,7 @@ func (s *ValidatorSuite) SetupSubTest() { } func (s *ValidatorSuite) TearDownSubTest() { - repository = nil + repo = nil validator = nil } @@ -53,24 +55,24 @@ func (s *ValidatorSuite) TestItFailsWhenClaimDoesNotMatchMachineOutputsHash() { epochs := []Epoch{dummyEpochs[0]} epochs[0].AppAddress = app.ContractAddress mismatchedHash := randomHash() - repository.On( + repo.On( "GetProcessedEpochs", mock.Anything, epochs[0].AppAddress, ).Return(epochs, nil) - repository.On( + repo.On( "GetLastInputOutputsHash", mock.Anything, epochs[0].Index, epochs[0].AppAddress, ).Return(&mismatchedHash, nil) - repository.On( + repo.On( "GetOutputsProducedInBlockRange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, ).Return(nil, nil) - repository.On("GetPreviousEpoch", mock.Anything, mock.Anything).Return(nil, nil) + repo.On("GetPreviousEpoch", mock.Anything, mock.Anything).Return(nil, nil) err := validator.validateApplication(ctx, app) s.NotNil(err) s.ErrorContains(err, "claim does not match") - repository.AssertExpectations(s.T()) + repo.AssertExpectations(s.T()) }) // fails on the second epoch, do not process the third @@ -88,24 +90,24 @@ func (s *ValidatorSuite) TestItFailsWhenClaimDoesNotMatchMachineOutputsHash() { epochs[0].ClaimHash = &epoch0Claim mismatchedHash := randomHash() - repository.On( + repo.On( "GetProcessedEpochs", mock.Anything, app.ContractAddress, ).Return(epochs, nil).Once() - repository.On( + repo.On( "GetOutputsProducedInBlockRange", mock.Anything, mock.Anything, mock.Anything, mock.Anything, ).Return(nil, nil) - repository.On("GetPreviousEpoch", mock.Anything, epochs[0]).Return(nil, nil) - repository.On( + repo.On("GetPreviousEpoch", mock.Anything, epochs[0]).Return(nil, nil) + repo.On( "GetLastInputOutputsHash", mock.Anything, epochs[0].Index, epochs[0].AppAddress, ).Return(epochs[0].ClaimHash, nil) - repository.On( + repo.On( "GetLastInputOutputsHash", mock.Anything, epochs[1].Index, epochs[1].AppAddress, ).Return(&mismatchedHash, nil) - repository.On("GetPreviousEpoch", mock.Anything, epochs[1]).Return(epochs[0], nil) - repository.On( + repo.On("GetPreviousEpoch", mock.Anything, epochs[1]).Return(epochs[0], nil) + repo.On( "SetEpochClaimAndInsertProofsTransaction", mock.Anything, mock.Anything, mock.Anything, ).Return(nil).Once() @@ -113,7 +115,7 @@ func (s *ValidatorSuite) TestItFailsWhenClaimDoesNotMatchMachineOutputsHash() { err = validator.validateApplication(ctx, app) s.NotNil(err) s.ErrorContains(err, "claim does not match") - repository.AssertExpectations(s.T()) + repo.AssertExpectations(s.T()) }) // validates first app, fails on the first epoch of the second @@ -138,37 +140,37 @@ func (s *ValidatorSuite) TestItFailsWhenClaimDoesNotMatchMachineOutputsHash() { epochsApp1[0].ClaimHash = &epoch0Claim mismatchedHash := randomHash() - repository.On("GetAllRunningApplications", mock.Anything).Return(applications, nil) - repository.On( + repo.On("GetAllRunningApplications", mock.Anything).Return(applications, nil) + repo.On( "GetProcessedEpochs", mock.Anything, applications[0].ContractAddress, ).Return(epochsApp1, nil) - repository.On( + repo.On( "GetOutputsProducedInBlockRange", mock.Anything, applications[0].ContractAddress, mock.Anything, mock.Anything, ).Return(nil, nil) - repository.On("GetPreviousEpoch", mock.Anything, epochsApp1[0]).Return(nil, nil) - repository.On("GetPreviousEpoch", mock.Anything, epochsApp1[1]).Return(epochsApp1[0], nil) - repository.On( + repo.On("GetPreviousEpoch", mock.Anything, epochsApp1[0]).Return(nil, nil) + repo.On("GetPreviousEpoch", mock.Anything, epochsApp1[1]).Return(epochsApp1[0], nil) + repo.On( "GetLastInputOutputsHash", mock.Anything, epochsApp1[0].Index, epochsApp1[0].AppAddress, ).Return(epochsApp1[0].ClaimHash, nil) - repository.On( + repo.On( "GetLastInputOutputsHash", mock.Anything, epochsApp1[1].Index, epochsApp1[1].AppAddress, ).Return(epochsApp1[0].ClaimHash, nil) - repository.On( + repo.On( "SetEpochClaimAndInsertProofsTransaction", mock.Anything, mock.Anything, mock.Anything, ).Return(nil).Twice() - repository.On( + repo.On( "GetProcessedEpochs", mock.Anything, applications[1].ContractAddress, ).Return(epochsApp2, nil) - repository.On( + repo.On( "GetOutputsProducedInBlockRange", mock.Anything, applications[1].ContractAddress, mock.Anything, mock.Anything, ).Return(nil, nil) - repository.On("GetPreviousEpoch", mock.Anything, epochsApp2[0]).Return(nil, nil) - repository.On( + repo.On("GetPreviousEpoch", mock.Anything, epochsApp2[0]).Return(nil, nil) + repo.On( "GetLastInputOutputsHash", mock.Anything, epochsApp2[0].Index, epochsApp2[0].AppAddress, ).Return(&mismatchedHash, nil) @@ -176,7 +178,7 @@ func (s *ValidatorSuite) TestItFailsWhenClaimDoesNotMatchMachineOutputsHash() { err = validator.Run(ctx) s.NotNil(err) s.ErrorContains(err, "claim does not match") - repository.AssertExpectations(s.T()) + repo.AssertExpectations(s.T()) }) } @@ -198,15 +200,15 @@ func randomHash() Hash { return Hash(hash) } -type MockRepository struct { +type Mockrepo struct { mock.Mock } -func newMockRepository() *MockRepository { - return new(MockRepository) +func newMockrepo() *Mockrepo { + return new(Mockrepo) } -func (m *MockRepository) GetAllRunningApplications(ctx context.Context) ([]Application, error) { +func (m *Mockrepo) GetAllRunningApplications(ctx context.Context) ([]Application, error) { args := m.Called(ctx) apps, ok := args.Get(0).([]Application) @@ -216,7 +218,7 @@ func (m *MockRepository) GetAllRunningApplications(ctx context.Context) ([]Appli return nil, args.Error(1) } -func (m *MockRepository) GetOutputsProducedInBlockRange( +func (m *Mockrepo) GetOutputsProducedInBlockRange( ctx context.Context, application Address, firstBlock, lastBlock uint64, @@ -229,7 +231,7 @@ func (m *MockRepository) GetOutputsProducedInBlockRange( return nil, args.Error(1) } -func (m *MockRepository) GetProcessedEpochs( +func (m *Mockrepo) GetProcessedEpochs( ctx context.Context, application Address, ) ([]Epoch, error) { @@ -241,7 +243,7 @@ func (m *MockRepository) GetProcessedEpochs( return nil, args.Error(1) } -func (m *MockRepository) GetLastInputOutputsHash( +func (m *Mockrepo) GetLastInputOutputsHash( ctx context.Context, epochIndex uint64, appAddress Address, @@ -254,7 +256,7 @@ func (m *MockRepository) GetLastInputOutputsHash( return nil, args.Error(1) } -func (m *MockRepository) GetPreviousEpoch( +func (m *Mockrepo) GetPreviousEpoch( ctx context.Context, currentEpoch Epoch, ) (*Epoch, error) { @@ -266,7 +268,7 @@ func (m *MockRepository) GetPreviousEpoch( return nil, args.Error(1) } -func (m *MockRepository) SetEpochClaimAndInsertProofsTransaction( +func (m *Mockrepo) SetEpochClaimAndInsertProofsTransaction( ctx context.Context, epoch Epoch, outputs []Output, diff --git a/pkg/service/log.go b/pkg/service/log.go new file mode 100644 index 000000000..ea454a105 --- /dev/null +++ b/pkg/service/log.go @@ -0,0 +1,29 @@ +// Implementation of the pflags Value interface. +package service + +import ( + "log/slog" + "os" +) + +type LogLevel slog.Level +func (me LogLevel) String() string { + return slog.Level(me).String() +} +func (me *LogLevel) Set(s string) error { + m := map[string]slog.Level{ + "debug": slog.LevelDebug, + "info": slog.LevelInfo, + "warn": slog.LevelWarn, + "error": slog.LevelError, + } + if v, ok := m[s]; ok { + *me = LogLevel(v) + return nil + } else { + return os.ErrNotExist + } +} +func (me *LogLevel) Type() string { + return "service.LogLevel" +} diff --git a/pkg/service/service.go b/pkg/service/service.go index 68892efb1..afb1db1c0 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -81,7 +81,7 @@ type ServiceImpl interface { type CreateInfo struct { Name string Impl ServiceImpl - LogLevel string + LogLevel LogLevel ProcOwner bool ServeMux *http.ServeMux Context context.Context @@ -135,18 +135,7 @@ func Create(ci *CreateInfo, s *Service) error { } // log - var LogLevel slog.Level if s.Logger == nil { - LogLevel = map[string]slog.Level{ - "debug": slog.LevelDebug, - "info": slog.LevelInfo, - "warn": slog.LevelWarn, - "error": slog.LevelError, - }[ci.LogLevel] - - if ci.LogLevel == "" { - LogLevel = slog.LevelDebug - } // opts := &tint.Options{ // Level: LogLevel, // AddSource: LogLevel == slog.LevelDebug, @@ -198,7 +187,7 @@ func Create(ci *CreateInfo, s *Service) error { s.Logger.Warn("Create:Created a new ServeMux", "service", s.Name, "ProcOwner", ci.ProcOwner, - "LogLevel", LogLevel) + "LogLevel", ci.LogLevel) } ci.ServeMux = http.NewServeMux() } @@ -216,13 +205,13 @@ func Create(ci *CreateInfo, s *Service) error { if ci.ProcOwner { s.Logger.Info("Create", "service", s.Name, - "LogLevel", LogLevel, + "LogLevel", ci.LogLevel, "pid", os.Getpid()) } else { s.Running.Store(true) s.Logger.Info("Create", "service", s.Name, - "LogLevel", LogLevel) + "LogLevel", ci.LogLevel) } return nil } diff --git a/test/validator/validator_test.go b/test/validator/validator_test.go index 5bf219869..afe6cba76 100644 --- a/test/validator/validator_test.go +++ b/test/validator/validator_test.go @@ -12,6 +12,7 @@ import ( "github.com/cartesi/rollups-node/internal/model" "github.com/cartesi/rollups-node/internal/repository" "github.com/cartesi/rollups-node/internal/validator" + "github.com/cartesi/rollups-node/pkg/service" "github.com/cartesi/rollups-node/test/tooling/db" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -24,7 +25,7 @@ type ValidatorRepositoryIntegrationSuite struct { suite.Suite ctx context.Context cancel context.CancelFunc - validator *validator.Validator + validator validator.Service database *repository.Database postgresEndpoint string } @@ -50,15 +51,20 @@ func (s *ValidatorRepositoryIntegrationSuite) SetupSubTest() { s.database, err = repository.Connect(s.ctx, s.postgresEndpoint) s.Require().Nil(err) - s.validator = validator.NewValidator(s.database, 0) - err = db.SetupTestPostgres(s.postgresEndpoint) s.Require().Nil(err) + + c := validator.CreateInfo{ + CreateInfo: service.CreateInfo{ + Name: "validator", + Impl: &s.validator, + }, + Repository: s.database, + } + s.Require().Nil(validator.Create(c, &s.validator)) } func (s *ValidatorRepositoryIntegrationSuite) TearDownSubTest() { - s.validator = nil - s.database.Close() }