github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/types/genesis.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"time"
    10  
    11  	"github.com/tendermint/tendermint/crypto"
    12  	tmbytes "github.com/tendermint/tendermint/libs/bytes"
    13  	tmjson "github.com/tendermint/tendermint/libs/json"
    14  	tmos "github.com/tendermint/tendermint/libs/os"
    15  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    16  	tmtime "github.com/tendermint/tendermint/types/time"
    17  )
    18  
    19  const (
    20  	// MaxChainIDLen is a maximum length of the chain ID.
    21  	MaxChainIDLen = 50
    22  )
    23  
    24  //------------------------------------------------------------
    25  // core types for a genesis definition
    26  // NOTE: any changes to the genesis definition should
    27  // be reflected in the documentation:
    28  // docs/tendermint-core/using-tendermint.md
    29  
    30  // GenesisValidator is an initial validator.
    31  type GenesisValidator struct {
    32  	Address Address       `json:"address"`
    33  	PubKey  crypto.PubKey `json:"pub_key"`
    34  	Power   int64         `json:"power"`
    35  	Name    string        `json:"name"`
    36  }
    37  
    38  // GenesisDoc defines the initial conditions for a tendermint blockchain, in particular its validator set.
    39  type GenesisDoc struct {
    40  	GenesisTime     time.Time                `json:"genesis_time"`
    41  	ChainID         string                   `json:"chain_id"`
    42  	ConsensusParams *tmproto.ConsensusParams `json:"consensus_params,omitempty"`
    43  	Validators      []GenesisValidator       `json:"validators,omitempty"`
    44  	AppHash         tmbytes.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 := tmjson.MarshalIndent(genDoc, "", "  ")
    51  	if err != nil {
    52  		return err
    53  	}
    54  	return tmos.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  
    77  	if genDoc.ConsensusParams == nil {
    78  		genDoc.ConsensusParams = DefaultConsensusParams()
    79  	} else if err := ValidateConsensusParams(*genDoc.ConsensusParams); err != nil {
    80  		return err
    81  	}
    82  
    83  	for i, v := range genDoc.Validators {
    84  		if v.Power == 0 {
    85  			return fmt.Errorf("the genesis file cannot contain validators with no voting power: %v", v)
    86  		}
    87  		if len(v.Address) > 0 && !bytes.Equal(v.PubKey.Address(), v.Address) {
    88  			return fmt.Errorf("incorrect address for validator %v in the genesis file, should be %v", v, v.PubKey.Address())
    89  		}
    90  		if len(v.Address) == 0 {
    91  			genDoc.Validators[i].Address = v.PubKey.Address()
    92  		}
    93  	}
    94  
    95  	if genDoc.GenesisTime.IsZero() {
    96  		genDoc.GenesisTime = tmtime.Now()
    97  	}
    98  
    99  	return nil
   100  }
   101  
   102  //------------------------------------------------------------
   103  // Make genesis state from file
   104  
   105  // GenesisDocFromJSON unmarshalls JSON data into a GenesisDoc.
   106  func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) {
   107  	genDoc := GenesisDoc{}
   108  	err := tmjson.Unmarshal(jsonBlob, &genDoc)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	if err := genDoc.ValidateAndComplete(); err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	return &genDoc, err
   118  }
   119  
   120  // GenesisDocFromFile reads JSON data from a file and unmarshalls it into a GenesisDoc.
   121  func GenesisDocFromFile(genDocFile string) (*GenesisDoc, error) {
   122  	jsonBlob, err := ioutil.ReadFile(genDocFile)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("couldn't read GenesisDoc file: %w", err)
   125  	}
   126  	genDoc, err := GenesisDocFromJSON(jsonBlob)
   127  	if err != nil {
   128  		return nil, fmt.Errorf("error reading GenesisDoc at %s: %w", genDocFile, err)
   129  	}
   130  	return genDoc, nil
   131  }