github.com/okex/exchain@v1.8.0/libs/tendermint/types/genesis.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "time" 9 10 "github.com/pkg/errors" 11 12 "github.com/okex/exchain/libs/tendermint/crypto" 13 tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes" 14 tmos "github.com/okex/exchain/libs/tendermint/libs/os" 15 tmtime "github.com/okex/exchain/libs/tendermint/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/tendermint-core/using-tendermint.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 tendermint blockchain, in particular its validator set. 38 type GenesisDoc struct { 39 GenesisTime time.Time `json:"genesis_time"` 40 ChainID string `json:"chain_id"` 41 ConsensusParams *ConsensusParams `json:"consensus_params,omitempty"` 42 Validators []GenesisValidator `json:"validators,omitempty"` 43 AppHash tmbytes.HexBytes `json:"app_hash"` 44 AppState json.RawMessage `json:"app_state,omitempty"` 45 } 46 47 // SaveAs is a utility method for saving GenensisDoc as a JSON file. 48 func (genDoc *GenesisDoc) SaveAs(file string) error { 49 genDocBytes, err := cdc.MarshalJSONIndent(genDoc, "", " ") 50 if err != nil { 51 return err 52 } 53 54 var genDocRaw struct { 55 GenesisTime string `json:"genesis_time"` 56 ChainID string `json:"chain_id"` 57 ConsensusParams json.RawMessage `json:"consensus_params,omitempty"` 58 Validators []json.RawMessage `json:"validators,omitempty"` 59 AppHash string `json:"app_hash"` 60 AppState json.RawMessage `json:"app_state,omitempty"` 61 } 62 err = json.Unmarshal(genDocBytes, &genDocRaw) 63 if err != nil { 64 return err 65 } 66 var appStateObj interface{} 67 err = json.Unmarshal(genDocRaw.AppState, &appStateObj) 68 if err != nil { 69 return err 70 } 71 sortedAppStateBytes, err := json.Marshal(appStateObj) 72 if err != nil { 73 return err 74 } 75 genDocRaw.AppState = sortedAppStateBytes 76 genDocBytes, err = json.MarshalIndent(genDocRaw, "", " ") 77 if err != nil { 78 return err 79 } 80 return tmos.WriteFile(file, genDocBytes, 0644) 81 } 82 83 // ValidatorHash returns the hash of the validator set contained in the GenesisDoc 84 func (genDoc *GenesisDoc) ValidatorHash() []byte { 85 vals := make([]*Validator, len(genDoc.Validators)) 86 for i, v := range genDoc.Validators { 87 vals[i] = NewValidator(v.PubKey, v.Power) 88 } 89 vset := NewValidatorSet(vals) 90 return vset.Hash(genesisHeight) 91 } 92 93 // ValidateAndComplete checks that all necessary fields are present 94 // and fills in defaults for optional fields left empty 95 func (genDoc *GenesisDoc) ValidateAndComplete() error { 96 if genDoc.ChainID == "" { 97 return errors.New("genesis doc must include non-empty chain_id") 98 } 99 if len(genDoc.ChainID) > MaxChainIDLen { 100 return errors.Errorf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen) 101 } 102 103 if genDoc.ConsensusParams == nil { 104 genDoc.ConsensusParams = DefaultConsensusParams() 105 } else if err := genDoc.ConsensusParams.Validate(); err != nil { 106 return err 107 } 108 109 for i, v := range genDoc.Validators { 110 if v.Power == 0 { 111 return errors.Errorf("the genesis file cannot contain validators with no voting power: %v", v) 112 } 113 if len(v.Address) > 0 && !bytes.Equal(v.PubKey.Address(), v.Address) { 114 return errors.Errorf("incorrect address for validator %v in the genesis file, should be %v", v, v.PubKey.Address()) 115 } 116 if len(v.Address) == 0 { 117 genDoc.Validators[i].Address = v.PubKey.Address() 118 } 119 } 120 121 if genDoc.GenesisTime.IsZero() { 122 genDoc.GenesisTime = tmtime.Now() 123 } 124 125 return nil 126 } 127 128 //------------------------------------------------------------ 129 // Make genesis state from file 130 131 // GenesisDocFromJSON unmarshalls JSON data into a GenesisDoc. 132 func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) { 133 genDoc := GenesisDoc{} 134 err := cdc.UnmarshalJSON(jsonBlob, &genDoc) 135 if err != nil { 136 return nil, err 137 } 138 139 if err := genDoc.ValidateAndComplete(); err != nil { 140 return nil, err 141 } 142 143 return &genDoc, err 144 } 145 146 // GenesisDocFromFile reads JSON data from a file and unmarshalls it into a GenesisDoc. 147 func GenesisDocFromFile(genDocFile string) (*GenesisDoc, error) { 148 jsonBlob, err := ioutil.ReadFile(genDocFile) 149 if err != nil { 150 return nil, errors.Wrap(err, "Couldn't read GenesisDoc file") 151 } 152 genDoc, err := GenesisDocFromJSON(jsonBlob) 153 if err != nil { 154 return nil, errors.Wrap(err, fmt.Sprintf("Error reading GenesisDoc at %v", genDocFile)) 155 } 156 return genDoc, nil 157 }