github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/tm/crypto"
    12  	tmbytes "github.com/vipernet-xyz/tm/libs/bytes"
    13  	tmjson "github.com/vipernet-xyz/tm/libs/json"
    14  	tmos "github.com/vipernet-xyz/tm/libs/os"
    15  	tmproto "github.com/vipernet-xyz/tm/proto/tendermint/types"
    16  	tmtime "github.com/vipernet-xyz/tm/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  	InitialHeight   int64                    `json:"initial_height"`
    43  	ConsensusParams *tmproto.ConsensusParams `json:"consensus_params,omitempty"`
    44  	Validators      []GenesisValidator       `json:"validators,omitempty"`
    45  	AppHash         tmbytes.HexBytes         `json:"app_hash"`
    46  	AppState        json.RawMessage          `json:"app_state,omitempty"`
    47  }
    48  
    49  // SaveAs is a utility method for saving GenensisDoc as a JSON file.
    50  func (genDoc *GenesisDoc) SaveAs(file string) error {
    51  	genDocBytes, err := tmjson.MarshalIndent(genDoc, "", "  ")
    52  	if err != nil {
    53  		return err
    54  	}
    55  	return tmos.WriteFile(file, genDocBytes, 0o644)
    56  }
    57  
    58  // ValidatorHash returns the hash of the validator set contained in the GenesisDoc
    59  func (genDoc *GenesisDoc) ValidatorHash() []byte {
    60  	vals := make([]*Validator, len(genDoc.Validators))
    61  	for i, v := range genDoc.Validators {
    62  		vals[i] = NewValidator(v.PubKey, v.Power)
    63  	}
    64  	vset := NewValidatorSet(vals)
    65  	return vset.Hash()
    66  }
    67  
    68  // ValidateAndComplete checks that all necessary fields are present
    69  // and fills in defaults for optional fields left empty
    70  func (genDoc *GenesisDoc) ValidateAndComplete() error {
    71  	if genDoc.ChainID == "" {
    72  		return errors.New("genesis doc must include non-empty chain_id")
    73  	}
    74  	if len(genDoc.ChainID) > MaxChainIDLen {
    75  		return fmt.Errorf("chain_id in genesis doc is too long (max: %d)", MaxChainIDLen)
    76  	}
    77  	if genDoc.InitialHeight < 0 {
    78  		return fmt.Errorf("initial_height cannot be negative (got %v)", genDoc.InitialHeight)
    79  	}
    80  	if genDoc.InitialHeight == 0 {
    81  		genDoc.InitialHeight = 1
    82  	}
    83  
    84  	if genDoc.ConsensusParams == nil {
    85  		genDoc.ConsensusParams = DefaultConsensusParams()
    86  	} else if err := ValidateConsensusParams(*genDoc.ConsensusParams); err != nil {
    87  		return err
    88  	}
    89  
    90  	for i, v := range genDoc.Validators {
    91  		if v.Power == 0 {
    92  			return fmt.Errorf("the genesis file cannot contain validators with no voting power: %v", v)
    93  		}
    94  		if len(v.Address) > 0 && !bytes.Equal(v.PubKey.Address(), v.Address) {
    95  			return fmt.Errorf("incorrect address for validator %v in the genesis file, should be %v", v, v.PubKey.Address())
    96  		}
    97  		if len(v.Address) == 0 {
    98  			genDoc.Validators[i].Address = v.PubKey.Address()
    99  		}
   100  	}
   101  
   102  	if genDoc.GenesisTime.IsZero() {
   103  		genDoc.GenesisTime = tmtime.Now()
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  //------------------------------------------------------------
   110  // Make genesis state from file
   111  
   112  // GenesisDocFromJSON unmarshalls JSON data into a GenesisDoc.
   113  func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) {
   114  	genDoc := GenesisDoc{}
   115  	err := tmjson.Unmarshal(jsonBlob, &genDoc)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	if err := genDoc.ValidateAndComplete(); err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	return &genDoc, err
   125  }
   126  
   127  // GenesisDocFromFile reads JSON data from a file and unmarshalls it into a GenesisDoc.
   128  func GenesisDocFromFile(genDocFile string) (*GenesisDoc, error) {
   129  	jsonBlob, err := os.ReadFile(genDocFile)
   130  	if err != nil {
   131  		return nil, fmt.Errorf("couldn't read GenesisDoc file: %w", err)
   132  	}
   133  	genDoc, err := GenesisDocFromJSON(jsonBlob)
   134  	if err != nil {
   135  		return nil, fmt.Errorf("error reading GenesisDoc at %s: %w", genDocFile, err)
   136  	}
   137  	return genDoc, nil
   138  }