code.vegaprotocol.io/vega@v0.79.0/cmd/data-node/commands/networkhistory/show.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 networkhistory 17 18 import ( 19 "context" 20 "fmt" 21 "os" 22 "sort" 23 24 coreConfig "code.vegaprotocol.io/vega/core/config" 25 "code.vegaprotocol.io/vega/datanode/config" 26 "code.vegaprotocol.io/vega/datanode/networkhistory/segment" 27 "code.vegaprotocol.io/vega/datanode/sqlstore" 28 vgjson "code.vegaprotocol.io/vega/libs/json" 29 "code.vegaprotocol.io/vega/logging" 30 "code.vegaprotocol.io/vega/paths" 31 v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2" 32 33 "github.com/jackc/pgx/v4/pgxpool" 34 ) 35 36 type showCmd struct { 37 config.VegaHomeFlag 38 config.Config 39 coreConfig.OutputFlag 40 41 AllSegments bool `description:"show all segments for each contiguous history" long:"segments" short:"s"` 42 } 43 44 type showOutput struct { 45 Segments []*v2.HistorySegment 46 ContiguousHistories []segment.ContiguousHistory[*v2.HistorySegment] 47 DataNodeBlockStart int64 48 DataNodeBlockEnd int64 49 } 50 51 func (o *showOutput) printHuman(allSegments bool) { 52 if len(o.ContiguousHistories) > 0 { 53 fmt.Printf("Available contiguous history spans:") 54 for _, contiguousHistory := range o.ContiguousHistories { 55 fmt.Printf("\n\nContiguous history from block height %d to %d, from segment id: %s to %s\n", 56 contiguousHistory.HeightFrom, 57 contiguousHistory.HeightTo, 58 contiguousHistory.Segments[0].GetHistorySegmentId(), 59 contiguousHistory.Segments[len(contiguousHistory.Segments)-1].GetHistorySegmentId(), 60 ) 61 62 if allSegments { 63 for _, segment := range contiguousHistory.Segments { 64 fmt.Printf("\n%d to %d, id: %s, previous segment id: %s", 65 segment.GetFromHeight(), 66 segment.GetToHeight(), 67 segment.GetHistorySegmentId(), 68 segment.GetPreviousHistorySegmentId()) 69 } 70 } 71 } 72 } else { 73 fmt.Printf("\nNo network history is available. Use the fetch command to fetch network history\n") 74 } 75 76 if o.DataNodeBlockEnd > 0 { 77 fmt.Printf("\n\nDatanode currently has data from block height %d to %d\n", o.DataNodeBlockStart, o.DataNodeBlockEnd) 78 } else { 79 fmt.Printf("\n\nDatanode contains no data\n") 80 } 81 } 82 83 func (cmd *showCmd) Execute(_ []string) error { 84 ctx, cfunc := context.WithCancel(context.Background()) 85 defer cfunc() 86 cfg := logging.NewDefaultConfig() 87 cfg.Custom.Zap.Level = logging.WarnLevel 88 cfg.Environment = "custom" 89 log := logging.NewLoggerFromConfig( 90 cfg, 91 ) 92 defer log.AtExit() 93 94 vegaPaths := paths.New(cmd.VegaHome) 95 err := fixConfig(&cmd.Config, vegaPaths) 96 if err != nil { 97 handleErr(log, cmd.Output.IsJSON(), "failed to fix config", err) 98 os.Exit(1) 99 } 100 101 if !datanodeLive(cmd.Config) { 102 handleErr(log, 103 cmd.Output.IsJSON(), 104 "datanode must be running for this command to work", 105 fmt.Errorf("couldn't connect to datanode on %v:%v", cmd.Config.API.IP, cmd.Config.API.Port)) 106 os.Exit(1) 107 } 108 109 client, conn, err := getDatanodeClient(cmd.Config) 110 if err != nil { 111 handleErr(log, cmd.Output.IsJSON(), "failed to get datanode client", err) 112 os.Exit(1) 113 } 114 defer func() { _ = conn.Close() }() 115 116 response, err := client.ListAllNetworkHistorySegments(ctx, &v2.ListAllNetworkHistorySegmentsRequest{}) 117 if err != nil { 118 handleErr(log, cmd.Output.IsJSON(), "failed to list all network history segments", err) 119 os.Exit(1) 120 } 121 122 output := showOutput{} 123 output.Segments = response.Segments 124 125 sort.Slice(output.Segments, func(i int, j int) bool { 126 return output.Segments[i].ToHeight < output.Segments[j].ToHeight 127 }) 128 129 segments := segment.Segments[*v2.HistorySegment](response.Segments) 130 output.ContiguousHistories = segments.AllContigousHistories() 131 132 pool, err := getCommandConnPool(ctx, cmd.Config.SQLStore.ConnectionConfig) 133 if err != nil { 134 handleErr(log, cmd.Output.IsJSON(), "failed to get command conn pool", err) 135 } 136 defer pool.Close() 137 138 span, err := sqlstore.GetDatanodeBlockSpan(ctx, pool) 139 if err != nil { 140 handleErr(log, cmd.Output.IsJSON(), "failed to get datanode block span", err) 141 os.Exit(1) 142 } 143 144 if span.HasData { 145 output.DataNodeBlockStart = span.FromHeight 146 output.DataNodeBlockEnd = span.ToHeight 147 } 148 149 if cmd.Output.IsJSON() { 150 if err := vgjson.Print(&output); err != nil { 151 handleErr(log, cmd.Output.IsJSON(), "failed to marshal output", err) 152 os.Exit(1) 153 } 154 } else { 155 output.printHuman(cmd.AllSegments) 156 } 157 158 return nil 159 } 160 161 func getCommandConnPool(ctx context.Context, conf sqlstore.ConnectionConfig) (*pgxpool.Pool, error) { 162 conf.MaxConnPoolSize = 3 163 164 connPool, err := sqlstore.CreateConnectionPool(ctx, conf) 165 if err != nil { 166 return nil, fmt.Errorf("failed to create connection pool: %w", err) 167 } 168 169 return connPool, nil 170 }