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