code.vegaprotocol.io/vega@v0.79.0/cmd/data-node/commands/last-block.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package commands 17 18 import ( 19 "context" 20 "fmt" 21 "os" 22 "time" 23 24 coreConfig "code.vegaprotocol.io/vega/core/config" 25 "code.vegaprotocol.io/vega/datanode/config" 26 vgjson "code.vegaprotocol.io/vega/libs/json" 27 "code.vegaprotocol.io/vega/logging" 28 "code.vegaprotocol.io/vega/paths" 29 30 "github.com/cenkalti/backoff/v4" 31 "github.com/jackc/pgx/v4" 32 "github.com/jessevdk/go-flags" 33 ) 34 35 type LastBlockCmd struct { 36 config.VegaHomeFlag 37 coreConfig.OutputFlag 38 *config.Config 39 40 Timeout time.Duration `default:"10s" description:"Database connection timeout" long:"timeout"` 41 } 42 43 var lastBlockCmd LastBlockCmd 44 45 func (cmd *LastBlockCmd) Execute(_ []string) error { 46 log := logging.NewLoggerFromConfig(logging.NewDefaultConfig()) 47 defer log.AtExit() 48 49 vegaPaths := paths.New(cmd.VegaHome) 50 51 cfgLoader, err := config.InitialiseLoader(vegaPaths) 52 if err != nil { 53 return fmt.Errorf("couldn't initialise configuration loader: %w", err) 54 } 55 56 cmd.Config, err = cfgLoader.Get() 57 if err != nil { 58 handleErr(log, cmd.Output.IsJSON(), "couldn't load configuration", err) 59 os.Exit(1) 60 } 61 62 connectionString := cmd.Config.SQLStore.ConnectionConfig.GetConnectionString() 63 64 ctx, cancel := context.WithTimeout(context.Background(), cmd.Timeout) 65 defer cancel() 66 var conn *pgx.Conn 67 68 expBackoff := backoff.NewExponentialBackOff() 69 expBackoff.InitialInterval = time.Second 70 expBackoff.MaxInterval = time.Second 71 expBackoff.MaxElapsedTime = cmd.Timeout 72 73 // Retry the connect in case we have to wait for the database to start 74 err = backoff.Retry(func() (opErr error) { 75 conn, opErr = pgx.Connect(ctx, connectionString) 76 return opErr 77 }, expBackoff) 78 if err != nil { 79 handleErr(log, cmd.Output.IsJSON(), "Failed to connect to database", err) 80 os.Exit(1) 81 } 82 83 var lastBlock int64 84 err = conn.QueryRow(ctx, "select max(height) from blocks").Scan(&lastBlock) 85 if err != nil { 86 handleErr(log, cmd.Output.IsJSON(), "Failed to get last block", err) 87 os.Exit(1) 88 } 89 90 if cmd.Output.IsJSON() { 91 return vgjson.Print(struct { 92 LastBlock int64 `json:"last_block"` 93 }{ 94 LastBlock: lastBlock, 95 }) 96 } 97 98 log.Info("Last block", logging.Int64("height", lastBlock)) 99 return nil 100 } 101 102 func LastBlock(ctx context.Context, parser *flags.Parser) error { 103 cfg := config.NewDefaultConfig() 104 lastBlockCmd = LastBlockCmd{ 105 Config: &cfg, 106 } 107 _, err := parser.AddCommand("last-block", "Get last block", "Get last block", &lastBlockCmd) 108 return err 109 } 110 111 func handleErr(log *logging.Logger, outputJSON bool, msg string, err error) { 112 if outputJSON { 113 _ = vgjson.Print(struct { 114 Error string `json:"error"` 115 }{ 116 Error: err.Error(), 117 }) 118 return 119 } 120 log.Error(msg, logging.Error(err)) 121 }