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  }