github.com/cosmos/cosmos-sdk@v0.50.10/x/genutil/types/genesis.go (about) 1 package types 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io" 10 "os" 11 "path/filepath" 12 "time" 13 14 cmtjson "github.com/cometbft/cometbft/libs/json" 15 cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" 16 cmttypes "github.com/cometbft/cometbft/types" 17 cmttime "github.com/cometbft/cometbft/types/time" 18 19 "github.com/cosmos/cosmos-sdk/version" 20 ) 21 22 const ( 23 // MaxChainIDLen is the maximum length of a chain ID. 24 MaxChainIDLen = cmttypes.MaxChainIDLen 25 ) 26 27 // AppGenesis defines the app's genesis. 28 type AppGenesis struct { 29 AppName string `json:"app_name"` 30 AppVersion string `json:"app_version"` 31 GenesisTime time.Time `json:"genesis_time"` 32 ChainID string `json:"chain_id"` 33 InitialHeight int64 `json:"initial_height"` 34 AppHash []byte `json:"app_hash"` 35 AppState json.RawMessage `json:"app_state,omitempty"` 36 Consensus *ConsensusGenesis `json:"consensus,omitempty"` 37 } 38 39 // NewAppGenesisWithVersion returns a new AppGenesis with the app name and app version already. 40 func NewAppGenesisWithVersion(chainID string, appState json.RawMessage) *AppGenesis { 41 return &AppGenesis{ 42 AppName: version.AppName, 43 AppVersion: version.Version, 44 ChainID: chainID, 45 AppState: appState, 46 Consensus: &ConsensusGenesis{ 47 Validators: nil, 48 }, 49 } 50 } 51 52 // ValidateAndComplete performs validation and completes the AppGenesis. 53 func (ag *AppGenesis) ValidateAndComplete() error { 54 if ag.ChainID == "" { 55 return errors.New("genesis doc must include non-empty chain_id") 56 } 57 58 if len(ag.ChainID) > MaxChainIDLen { 59 return fmt.Errorf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen) 60 } 61 62 if ag.InitialHeight < 0 { 63 return fmt.Errorf("initial_height cannot be negative (got %v)", ag.InitialHeight) 64 } 65 66 if ag.InitialHeight == 0 { 67 ag.InitialHeight = 1 68 } 69 70 if ag.GenesisTime.IsZero() { 71 ag.GenesisTime = cmttime.Now() 72 } 73 74 if err := ag.Consensus.ValidateAndComplete(); err != nil { 75 return err 76 } 77 78 return nil 79 } 80 81 // SaveAs is a utility method for saving AppGenesis as a JSON file. 82 func (ag *AppGenesis) SaveAs(file string) error { 83 appGenesisBytes, err := json.MarshalIndent(ag, "", " ") 84 if err != nil { 85 return err 86 } 87 88 return os.WriteFile(file, appGenesisBytes, 0o600) 89 } 90 91 // AppGenesisFromReader reads the AppGenesis from the reader. 92 func AppGenesisFromReader(reader io.Reader) (*AppGenesis, error) { 93 jsonBlob, err := io.ReadAll(reader) 94 if err != nil { 95 return nil, err 96 } 97 98 var appGenesis AppGenesis 99 if err := json.Unmarshal(jsonBlob, &appGenesis); err != nil { 100 // fallback to CometBFT genesis 101 var ctmGenesis cmttypes.GenesisDoc 102 if err2 := cmtjson.Unmarshal(jsonBlob, &ctmGenesis); err2 != nil { 103 return nil, fmt.Errorf("error unmarshalling AppGenesis: %w\n failed fallback to CometBFT GenDoc: %w", err, err2) 104 } 105 106 appGenesis = AppGenesis{ 107 AppName: version.AppName, 108 // AppVersion is not filled as we do not know it from a CometBFT genesis 109 GenesisTime: ctmGenesis.GenesisTime, 110 ChainID: ctmGenesis.ChainID, 111 InitialHeight: ctmGenesis.InitialHeight, 112 AppHash: ctmGenesis.AppHash, 113 AppState: ctmGenesis.AppState, 114 Consensus: &ConsensusGenesis{ 115 Validators: ctmGenesis.Validators, 116 Params: ctmGenesis.ConsensusParams, 117 }, 118 } 119 } 120 121 return &appGenesis, nil 122 } 123 124 // AppGenesisFromFile reads the AppGenesis from the provided file. 125 func AppGenesisFromFile(genFile string) (*AppGenesis, error) { 126 file, err := os.Open(filepath.Clean(genFile)) 127 if err != nil { 128 return nil, err 129 } 130 131 appGenesis, err := AppGenesisFromReader(bufio.NewReader(file)) 132 if err != nil { 133 return nil, fmt.Errorf("failed to read genesis from file %s: %w", genFile, err) 134 } 135 136 if err := file.Close(); err != nil { 137 return nil, err 138 } 139 140 return appGenesis, nil 141 } 142 143 // -------------------------- 144 // CometBFT Genesis Handling 145 // -------------------------- 146 147 // ToGenesisDoc converts the AppGenesis to a CometBFT GenesisDoc. 148 func (ag *AppGenesis) ToGenesisDoc() (*cmttypes.GenesisDoc, error) { 149 return &cmttypes.GenesisDoc{ 150 GenesisTime: ag.GenesisTime, 151 ChainID: ag.ChainID, 152 InitialHeight: ag.InitialHeight, 153 AppHash: ag.AppHash, 154 AppState: ag.AppState, 155 Validators: ag.Consensus.Validators, 156 ConsensusParams: ag.Consensus.Params, 157 }, nil 158 } 159 160 // ConsensusGenesis defines the consensus layer's genesis. 161 // TODO(@julienrbrt) eventually abstract from CometBFT types 162 type ConsensusGenesis struct { 163 Validators []cmttypes.GenesisValidator `json:"validators,omitempty"` 164 Params *cmttypes.ConsensusParams `json:"params,omitempty"` 165 } 166 167 // NewConsensusGenesis returns a ConsensusGenesis with given values. 168 // It takes a proto consensus params so it can called from server export command. 169 func NewConsensusGenesis(params cmtproto.ConsensusParams, validators []cmttypes.GenesisValidator) *ConsensusGenesis { 170 return &ConsensusGenesis{ 171 Params: &cmttypes.ConsensusParams{ 172 Block: cmttypes.BlockParams{ 173 MaxBytes: params.Block.MaxBytes, 174 MaxGas: params.Block.MaxGas, 175 }, 176 Evidence: cmttypes.EvidenceParams{ 177 MaxAgeNumBlocks: params.Evidence.MaxAgeNumBlocks, 178 MaxAgeDuration: params.Evidence.MaxAgeDuration, 179 MaxBytes: params.Evidence.MaxBytes, 180 }, 181 Validator: cmttypes.ValidatorParams{ 182 PubKeyTypes: params.Validator.PubKeyTypes, 183 }, 184 }, 185 Validators: validators, 186 } 187 } 188 189 func (cs *ConsensusGenesis) MarshalJSON() ([]byte, error) { 190 type Alias ConsensusGenesis 191 return cmtjson.Marshal(&Alias{ 192 Validators: cs.Validators, 193 Params: cs.Params, 194 }) 195 } 196 197 func (cs *ConsensusGenesis) UnmarshalJSON(b []byte) error { 198 type Alias ConsensusGenesis 199 200 result := Alias{} 201 if err := cmtjson.Unmarshal(b, &result); err != nil { 202 return err 203 } 204 205 cs.Params = result.Params 206 cs.Validators = result.Validators 207 208 return nil 209 } 210 211 func (cs *ConsensusGenesis) ValidateAndComplete() error { 212 if cs == nil { 213 return fmt.Errorf("consensus genesis cannot be nil") 214 } 215 216 if cs.Params == nil { 217 cs.Params = cmttypes.DefaultConsensusParams() 218 } else if err := cs.Params.ValidateBasic(); err != nil { 219 return err 220 } 221 222 for i, v := range cs.Validators { 223 if v.Power == 0 { 224 return fmt.Errorf("the genesis file cannot contain validators with no voting power: %v", v) 225 } 226 if len(v.Address) > 0 && !bytes.Equal(v.PubKey.Address(), v.Address) { 227 return fmt.Errorf("incorrect address for validator %v in the genesis file, should be %v", v, v.PubKey.Address()) 228 } 229 if len(v.Address) == 0 { 230 cs.Validators[i].Address = v.PubKey.Address() 231 } 232 } 233 234 return nil 235 }