code.vegaprotocol.io/vega@v0.79.0/cmd/vegatools/snapshot.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 tools
    17  
    18  import (
    19  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  
    23  	"code.vegaprotocol.io/vega/core/config"
    24  	"code.vegaprotocol.io/vega/paths"
    25  	"code.vegaprotocol.io/vega/vegatools/snapshotdb"
    26  
    27  	tmconfig "github.com/cometbft/cometbft/config"
    28  	"github.com/cometbft/cometbft/store"
    29  	"github.com/spf13/viper"
    30  )
    31  
    32  type snapshotCmd struct {
    33  	config.OutputFlag
    34  	DBPath               string `description:"path to snapshot state data"                                                  long:"db-path"           short:"d"`
    35  	SnapshotContentsPath string `description:"path to file where to write the content of a snapshot"                        long:"snapshot-contents" short:"c"`
    36  	BlockHeight          uint64 `description:"block-height of requested snapshot"                                           long:"block-height"      short:"b"`
    37  	SetProtocolUpgrade   bool   `description:"set protocol-upgrade flag to true in the latest snapshot"                     long:"set-pup"           short:"p"`
    38  	TendermintHome       string `description:"tendermint home directory, if set will print the last processed block height" long:"tendermint-home"`
    39  }
    40  
    41  func getLastProcessedBlock(homeDir string) (int64, error) {
    42  	conf := tmconfig.DefaultConfig()
    43  	if err := viper.Unmarshal(conf); err != nil {
    44  		return 0, err
    45  	}
    46  	conf.SetRoot(homeDir)
    47  
    48  	// lets get the last processed block from tendermint
    49  	blockStoreDB, err := tmconfig.DefaultDBProvider(&tmconfig.DBContext{ID: "blockstore", Config: conf})
    50  	if err != nil {
    51  		return 0, err
    52  	}
    53  	blockStore := store.NewBlockStore(blockStoreDB)
    54  	return blockStore.Height(), nil
    55  }
    56  
    57  func (opts *snapshotCmd) Execute(_ []string) error {
    58  	if opts.SnapshotContentsPath != "" && opts.BlockHeight == 0 {
    59  		return errors.New("must specify --block-height when using --write-payload")
    60  	}
    61  
    62  	db := opts.DBPath
    63  	if opts.DBPath == "" {
    64  		vegaPaths := paths.New(rootCmd.VegaHome)
    65  		db = vegaPaths.StatePathFor(paths.SnapshotStateHome)
    66  	}
    67  
    68  	if opts.SetProtocolUpgrade {
    69  		err := snapshotdb.SetProtocolUpgrade(paths.New(rootCmd.VegaHome))
    70  		return err
    71  	}
    72  
    73  	if opts.SnapshotContentsPath != "" {
    74  		fmt.Printf("finding payloads for block-height %d...\n", opts.BlockHeight)
    75  		err := snapshotdb.SavePayloadsToFile(db, opts.SnapshotContentsPath, opts.BlockHeight)
    76  		if err != nil {
    77  			return err
    78  		}
    79  		fmt.Printf("payloads saved to '%s'\n", opts.SnapshotContentsPath)
    80  		return nil
    81  	}
    82  
    83  	snapshots, invalid, err := snapshotdb.SnapshotData(db, opts.BlockHeight)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	var lastProcessedBlock int64
    89  	if opts.TendermintHome != "" {
    90  		if lastProcessedBlock, err = getLastProcessedBlock(opts.TendermintHome); err != nil {
    91  			return err
    92  		}
    93  	}
    94  
    95  	if opts.Output.IsJSON() {
    96  		o := struct {
    97  			Snapshots          []snapshotdb.Data `json:"snapshots"`
    98  			Invalid            []snapshotdb.Data `json:"invalidSnapshots,omitempty"`
    99  			LastProcessedBlock int64             `json:"lastProcessedBlock,omitempty"`
   100  		}{
   101  			Snapshots:          snapshots,
   102  			Invalid:            invalid,
   103  			LastProcessedBlock: lastProcessedBlock,
   104  		}
   105  		b, err := json.Marshal(o)
   106  		if err != nil {
   107  			return err
   108  		}
   109  		fmt.Println(string(b))
   110  		return nil
   111  	}
   112  
   113  	if lastProcessedBlock != 0 {
   114  		fmt.Printf("\nLast processed block: %d\n", lastProcessedBlock)
   115  	}
   116  
   117  	fmt.Println("\nSnapshots available:", len(snapshots))
   118  	for _, snap := range snapshots {
   119  		fmt.Printf("\tHeight: %d, Version: %d, Size %d, Hash: %s\n", snap.Height, snap.Version, snap.Size, snap.Hash)
   120  	}
   121  
   122  	if len(invalid) == 0 {
   123  		return nil
   124  	}
   125  	fmt.Println("Invalid snapshots:", len(invalid))
   126  	for _, snap := range invalid {
   127  		fmt.Printf("\tVersion: %d, Size %d, Hash: %s\n", snap.Version, snap.Size, snap.Hash)
   128  	}
   129  
   130  	return nil
   131  }