From ad1b09b90e4c00d1ff8cfca111a42e575ae9a2c5 Mon Sep 17 00:00:00 2001 From: Francisco Moura Date: Thu, 18 Jul 2024 12:14:39 -0300 Subject: [PATCH] feat(evm-reader): Add evm-reader command --- cmd/cartesi-rollups-evm-reader/main.go | 229 +++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 cmd/cartesi-rollups-evm-reader/main.go diff --git a/cmd/cartesi-rollups-evm-reader/main.go b/cmd/cartesi-rollups-evm-reader/main.go new file mode 100644 index 000000000..b3c029b42 --- /dev/null +++ b/cmd/cartesi-rollups-evm-reader/main.go @@ -0,0 +1,229 @@ +// (c) Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 (see LICENSE) + +package main + +import ( + "context" + "errors" + "log/slog" + "os" + "os/signal" + "syscall" + "time" + + "github.com/cartesi/rollups-node/internal/evmreader/service" + "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/jackc/pgx/v5" + + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/tint" + "github.com/mattn/go-isatty" + "github.com/spf13/cobra" +) + +var ( + // Should be overridden during the final release build with ldflags + // to contain the actual version number + buildVersion = "devel" +) + +const ( + CMD_NAME = "evm-reader" + devnetInputBoxDeploymentBlockNumber = uint64(16) +) + +var Cmd = &cobra.Command{ + Use: CMD_NAME, + Short: "Runs EVM Reader", + Long: `Runs EVM Reader in standalone mode`, + Run: run, +} +var ( + defaultBlock string + postgresEndpoint string + blockchainHttpEndpoint string + blockchainWsEndpoint string + inputBoxAddress string + inputBoxDeploymentBlockNumber uint64 + verbose bool +) + +func init() { + + Cmd.Flags().StringVarP(&defaultBlock, + "default-block", + "d", + "", + `Default block to be used when fetching new blocks. + One of 'latest', 'safe', 'pending', 'finalized'`) + + Cmd.Flags().StringVarP(&postgresEndpoint, + "postgres-endpoint", + "p", + "", + "Postgres endpoint") + + Cmd.Flags().StringVarP(&blockchainHttpEndpoint, + "blockchain-http-endpoint", + "b", + "", + "Blockchain HTTP Endpoint") + + Cmd.Flags().StringVarP(&blockchainWsEndpoint, + "blockchain-ws-endpoint", + "w", + "", + "Blockchain WS Endpoint") + + Cmd.Flags().StringVarP(&inputBoxAddress, + "inputbox-address", + "i", + "", + "Input Box contract address") + + Cmd.Flags().Uint64VarP(&inputBoxDeploymentBlockNumber, + "inputbox-block-number", + "n", + 0, + "Input Box deployment block number") + + Cmd.Flags().BoolVarP(&verbose, + "verbose", + "v", + false, + "enable verbose logging") +} + +func main() { + err := Cmd.Execute() + if err != nil { + os.Exit(1) + } +} + +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 + opts := &tint.Options{ + Level: c.LogLevel, + AddSource: c.LogLevel == slog.LevelDebug, + NoColor: !c.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) + slog.Info("Starting the Cartesi Rollups Node", "version", buildVersion, "config", c) + + // Validate Schema + schemaManager, err := repository.NewSchemaManager(c.PostgresEndpoint.Value) + if err != nil { + slog.Error("Node exited with an error", "error", err) + schemaManager.Close() + os.Exit(1) + } + err = schemaManager.ValidateSchemaVersion() + if err != nil { + slog.Error("Node exited with an error", "error", err) + schemaManager.Close() + os.Exit(1) + } + schemaManager.Close() + + database, err := repository.Connect(ctx, c.PostgresEndpoint.Value) + if err != nil { + slog.Error("Node couldn't connect to the database", "error", err) + os.Exit(1) + } + defer database.Close() + + nodePersistentConfig, err := database.GetNodeConfig(ctx) + if err != nil { + if !errors.Is(err, pgx.ErrNoRows) { + slog.Error("Could not retrieve config from Database", "error", err) + os.Exit(1) + } + } + + if nodePersistentConfig == nil { + nodePersistentConfig = &NodePersistentConfig{ + DefaultBlock: c.EvmReaderDefaultBlock, + InputBoxDeploymentBlock: uint64(c.ContractsInputBoxDeploymentBlockNumber), + InputBoxAddress: common.HexToAddress(c.ContractsInputBoxAddress), + ChainId: c.BlockchainID, + IConsensusAddress: common.HexToAddress(c.ContractsIConsensusAddress), + } + slog.Info( + "No persistent config found at the database. Setting it up", + "persistent config", + nodePersistentConfig, + ) + + err = database.InsertNodeConfig(ctx, nodePersistentConfig) + if err != nil { + slog.Error("Node couldn't insert database config", "error", err) + database.Close() + os.Exit(1) + } + } else { + slog.Info( + "Node was already configured. Using previous persistent config", + "persistent config", + nodePersistentConfig, + ) + } + + // 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) + } +}