code.vegaprotocol.io/vega@v0.79.0/cmd/vega/commands/genesis/load_checkpoint.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 genesis 17 18 import ( 19 "encoding/base64" 20 "encoding/hex" 21 "encoding/json" 22 "fmt" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "strings" 27 28 "code.vegaprotocol.io/vega/core/genesis" 29 vgtm "code.vegaprotocol.io/vega/core/tendermint" 30 "code.vegaprotocol.io/vega/core/types" 31 vgfs "code.vegaprotocol.io/vega/libs/fs" 32 "code.vegaprotocol.io/vega/logging" 33 34 tmjson "github.com/cometbft/cometbft/libs/json" 35 tmtypes "github.com/cometbft/cometbft/types" 36 "github.com/jessevdk/go-flags" 37 ) 38 39 type loadCheckpointCmd struct { 40 DryRun bool `description:"Display the genesis file without writing it" long:"dry-run"` 41 TmHome string `description:"The home path of tendermint" long:"tm-home" short:"t"` 42 GenesisFile string `description:"A genesis file to be updated" long:"genesis-file" short:"g"` 43 CheckpointPath string `description:"The path to the checkpoint file to load" long:"checkpoint-path" required:"true"` 44 } 45 46 func (opts *loadCheckpointCmd) Execute(_ []string) error { 47 log := logging.NewLoggerFromConfig( 48 logging.NewDefaultConfig(), 49 ) 50 defer log.AtExit() 51 52 if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil { 53 return err 54 } 55 56 var ( 57 genesisDoc *tmtypes.GenesisDoc 58 err error 59 tmConfig *vgtm.Config 60 ) 61 62 if len(opts.GenesisFile) > 0 { 63 genesisDoc, _, err = readGenesisFile(opts.GenesisFile) 64 } else { 65 tmConfig = vgtm.NewConfig(opts.TmHome) 66 genesisDoc, _, err = tmConfig.Genesis() 67 } 68 if err != nil { 69 return fmt.Errorf("couldn't get genesis file: %w", err) 70 } 71 72 appState := genesis.State{} 73 err = json.Unmarshal(genesisDoc.AppState, &appState) 74 if err != nil { 75 return err 76 } 77 78 f, err := os.Open(opts.CheckpointPath) 79 if err != nil { 80 return err 81 } 82 83 splits := strings.Split(filepath.Base(f.Name()), "-") 84 if len(splits) != 3 { 85 return fmt.Errorf("invalid checkpoint file name: `%v`", f.Name()) 86 } 87 88 expectHash := strings.TrimSuffix(splits[2], ".cp") 89 f.Close() 90 91 buf, err := ioutil.ReadFile(opts.CheckpointPath) 92 if err != nil { 93 return err 94 } 95 96 cpt := &types.CheckpointState{} 97 if err := cpt.SetState(buf); err != nil { 98 return fmt.Errorf("invalid restore checkpoint command: %w", err) 99 } 100 101 if hex.EncodeToString(cpt.Hash) != expectHash { 102 return fmt.Errorf("invalid hash, file name have hash `%s` but content hash is `%s`", expectHash, hex.EncodeToString(cpt.Hash)) 103 } 104 105 appState.Checkpoint.CheckpointHash = expectHash 106 appState.Checkpoint.CheckpointState = base64.StdEncoding.EncodeToString(buf) 107 108 if err := vgtm.AddAppStateToGenesis(genesisDoc, &appState); err != nil { 109 return fmt.Errorf("couldn't add app_state to genesis: %w", err) 110 } 111 112 if !opts.DryRun { 113 if len(opts.GenesisFile) > 0 { 114 if err := genesisDoc.SaveAs(opts.GenesisFile); err != nil { 115 return fmt.Errorf("couldn't save the genesis file: %w", err) 116 } 117 } else { 118 if err := tmConfig.SaveGenesis(genesisDoc); err != nil { 119 return fmt.Errorf("couldn't save genesis: %w", err) 120 } 121 } 122 } 123 124 prettifiedDoc, err := vgtm.Prettify(genesisDoc) 125 if err != nil { 126 return err 127 } 128 fmt.Println(prettifiedDoc) 129 return nil 130 } 131 132 func readGenesisFile(path string) (*tmtypes.GenesisDoc, *genesis.State, error) { 133 data, err := vgfs.ReadFile(path) 134 if err != nil { 135 return nil, nil, fmt.Errorf("couldn't read genesis file: %w", err) 136 } 137 138 doc := &tmtypes.GenesisDoc{} 139 err = tmjson.Unmarshal(data, doc) 140 if err != nil { 141 return nil, nil, fmt.Errorf("couldn't unmarshal the genesis document: %w", err) 142 } 143 144 state := &genesis.State{} 145 146 if len(doc.AppState) != 0 { 147 if err := json.Unmarshal(doc.AppState, state); err != nil { 148 return nil, nil, fmt.Errorf("couldn't unmarshal genesis state: %w", err) 149 } 150 } 151 152 return doc, state, nil 153 }