github.com/aakash4dev/cometbft@v0.38.2/types/genesis.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os" 9 "time" 10 11 "github.com/aakash4dev/cometbft/crypto" 12 cmtbytes "github.com/aakash4dev/cometbft/libs/bytes" 13 cmtjson "github.com/aakash4dev/cometbft/libs/json" 14 cmtos "github.com/aakash4dev/cometbft/libs/os" 15 cmttime "github.com/aakash4dev/cometbft/types/time" 16 ) 17 18 const ( 19 // MaxChainIDLen is a maximum length of the chain ID. 20 MaxChainIDLen = 50 21 ) 22 23 //------------------------------------------------------------ 24 // core types for a genesis definition 25 // NOTE: any changes to the genesis definition should 26 // be reflected in the documentation: 27 // docs/core/using-cometbft.md 28 29 // GenesisValidator is an initial validator. 30 type GenesisValidator struct { 31 Address Address `json:"address"` 32 PubKey crypto.PubKey `json:"pub_key"` 33 Power int64 `json:"power"` 34 Name string `json:"name"` 35 } 36 37 // GenesisDoc defines the initial conditions for a CometBFT blockchain, in particular its validator set. 38 type GenesisDoc struct { 39 GenesisTime time.Time `json:"genesis_time"` 40 ChainID string `json:"chain_id"` 41 InitialHeight int64 `json:"initial_height"` 42 ConsensusParams *ConsensusParams `json:"consensus_params,omitempty"` 43 Validators []GenesisValidator `json:"validators,omitempty"` 44 AppHash cmtbytes.HexBytes `json:"app_hash"` 45 AppState json.RawMessage `json:"app_state,omitempty"` 46 } 47 48 // SaveAs is a utility method for saving GenensisDoc as a JSON file. 49 func (genDoc *GenesisDoc) SaveAs(file string) error { 50 genDocBytes, err := cmtjson.MarshalIndent(genDoc, "", " ") 51 if err != nil { 52 return err 53 } 54 return cmtos.WriteFile(file, genDocBytes, 0644) 55 } 56 57 // ValidatorHash returns the hash of the validator set contained in the GenesisDoc 58 func (genDoc *GenesisDoc) ValidatorHash() []byte { 59 vals := make([]*Validator, len(genDoc.Validators)) 60 for i, v := range genDoc.Validators { 61 vals[i] = NewValidator(v.PubKey, v.Power) 62 } 63 vset := NewValidatorSet(vals) 64 return vset.Hash() 65 } 66 67 // ValidateAndComplete checks that all necessary fields are present 68 // and fills in defaults for optional fields left empty 69 func (genDoc *GenesisDoc) ValidateAndComplete() error { 70 if genDoc.ChainID == "" { 71 return errors.New("genesis doc must include non-empty chain_id") 72 } 73 if len(genDoc.ChainID) > MaxChainIDLen { 74 return fmt.Errorf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen) 75 } 76 if genDoc.InitialHeight < 0 { 77 return fmt.Errorf("initial_height cannot be negative (got %v)", genDoc.InitialHeight) 78 } 79 if genDoc.InitialHeight == 0 { 80 genDoc.InitialHeight = 1 81 } 82 83 if genDoc.ConsensusParams == nil { 84 genDoc.ConsensusParams = DefaultConsensusParams() 85 } else if err := genDoc.ConsensusParams.ValidateBasic(); err != nil { 86 return err 87 } 88 89 for i, v := range genDoc.Validators { 90 if v.Power == 0 { 91 return fmt.Errorf("the genesis file cannot contain validators with no voting power: %v", v) 92 } 93 if len(v.Address) > 0 && !bytes.Equal(v.PubKey.Address(), v.Address) { 94 return fmt.Errorf("incorrect address for validator %v in the genesis file, should be %v", v, v.PubKey.Address()) 95 } 96 if len(v.Address) == 0 { 97 genDoc.Validators[i].Address = v.PubKey.Address() 98 } 99 } 100 101 if genDoc.GenesisTime.IsZero() { 102 genDoc.GenesisTime = cmttime.Now() 103 } 104 105 return nil 106 } 107 108 //------------------------------------------------------------ 109 // Make genesis state from file 110 111 // GenesisDocFromJSON unmarshalls JSON data into a GenesisDoc. 112 func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) { 113 genDoc := GenesisDoc{} 114 err := cmtjson.Unmarshal(jsonBlob, &genDoc) 115 if err != nil { 116 return nil, err 117 } 118 119 if err := genDoc.ValidateAndComplete(); err != nil { 120 return nil, err 121 } 122 123 return &genDoc, err 124 } 125 126 // GenesisDocFromFile reads JSON data from a file and unmarshalls it into a GenesisDoc. 127 func GenesisDocFromFile(genDocFile string) (*GenesisDoc, error) { 128 jsonBlob, err := os.ReadFile(genDocFile) 129 if err != nil { 130 return nil, fmt.Errorf("couldn't read GenesisDoc file: %w", err) 131 } 132 genDoc, err := GenesisDocFromJSON(jsonBlob) 133 if err != nil { 134 return nil, fmt.Errorf("error reading GenesisDoc at %s: %w", genDocFile, err) 135 } 136 return genDoc, nil 137 }