github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/genesis/spec/genesis_spec.go (about)

     1  package spec
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"encoding/json"
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/hyperledger/burrow/acm/balance"
    11  	crypto "github.com/hyperledger/burrow/crypto"
    12  	"github.com/hyperledger/burrow/genesis"
    13  	"github.com/hyperledger/burrow/keys"
    14  	"github.com/hyperledger/burrow/permission"
    15  )
    16  
    17  const DefaultAmount uint64 = 1000000
    18  const DefaultPower uint64 = 10000
    19  
    20  // A GenesisSpec is schematic representation of a genesis state, that is it is a template
    21  // for a GenesisDoc excluding that which needs to be instantiated at the point of genesis
    22  // so it describes the type and number of accounts, the genesis salt, but not the
    23  // account keys or addresses, or the GenesisTime. It is responsible for generating keys
    24  // by interacting with the KeysClient it is passed and other information not known at
    25  // specification time
    26  type GenesisSpec struct {
    27  	GenesisTime       *time.Time        `json:",omitempty" toml:",omitempty"`
    28  	ChainName         string            `json:",omitempty" toml:",omitempty"`
    29  	Params            params            `json:",omitempty" toml:",omitempty"`
    30  	Salt              []byte            `json:",omitempty" toml:",omitempty"`
    31  	GlobalPermissions []string          `json:",omitempty" toml:",omitempty"`
    32  	Accounts          []TemplateAccount `json:",omitempty" toml:",omitempty"`
    33  }
    34  
    35  type params struct {
    36  	ProposalThreshold uint64 `json:",omitempty" toml:",omitempty"`
    37  }
    38  
    39  // Produce a fully realised GenesisDoc from a template GenesisDoc that may omit values
    40  func (gs *GenesisSpec) GenesisDoc(keyClient keys.KeyClient, curve crypto.CurveType) (*genesis.GenesisDoc, error) {
    41  	genesisDoc := new(genesis.GenesisDoc)
    42  	if gs.GenesisTime == nil {
    43  		genesisDoc.GenesisTime = time.Now()
    44  	} else {
    45  		genesisDoc.GenesisTime = *gs.GenesisTime
    46  	}
    47  
    48  	if gs.ChainName == "" {
    49  		genesisDoc.ChainName = fmt.Sprintf("BurrowChain_%X", gs.ShortHash())
    50  	} else {
    51  		genesisDoc.ChainName = gs.ChainName
    52  	}
    53  
    54  	if gs.Params.ProposalThreshold != 0 {
    55  		genesisDoc.Params.ProposalThreshold = genesis.DefaultProposalThreshold
    56  	}
    57  
    58  	if len(gs.GlobalPermissions) == 0 {
    59  		genesisDoc.GlobalPermissions = permission.DefaultAccountPermissions.Clone()
    60  	} else {
    61  		basePerms, err := permission.BasePermissionsFromStringList(gs.GlobalPermissions)
    62  		if err != nil {
    63  			return nil, err
    64  		}
    65  		genesisDoc.GlobalPermissions = permission.AccountPermissions{
    66  			Base: basePerms,
    67  		}
    68  	}
    69  
    70  	templateAccounts := gs.Accounts
    71  	if len(gs.Accounts) == 0 {
    72  		templateAccounts = append(templateAccounts, TemplateAccount{
    73  			Amounts: balance.New().Power(DefaultPower),
    74  		})
    75  	}
    76  
    77  	for i, templateAccount := range templateAccounts {
    78  		ct := curve
    79  		if templateAccount.Balances().HasPower() {
    80  			// currently only ed25519 is supported for validator keys
    81  			ct = crypto.CurveTypeEd25519
    82  		}
    83  
    84  		account, err := templateAccount.GenesisAccount(keyClient, i, ct)
    85  		if err != nil {
    86  			return nil, fmt.Errorf("could not create Account from template: %v", err)
    87  		}
    88  		genesisDoc.Accounts = append(genesisDoc.Accounts, *account)
    89  
    90  		if templateAccount.Balances().HasPower() {
    91  			// Note this does not modify the input template
    92  			templateAccount.Address = &account.Address
    93  			validator, err := templateAccount.Validator(keyClient, i, ct)
    94  			if err != nil {
    95  				return nil, fmt.Errorf("could not create Validator from template: %v", err)
    96  			}
    97  			genesisDoc.Validators = append(genesisDoc.Validators, *validator)
    98  		}
    99  	}
   100  
   101  	return genesisDoc, nil
   102  }
   103  
   104  func (gs *GenesisSpec) JSONBytes() ([]byte, error) {
   105  	bs, err := json.Marshal(gs)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	// rewrite buffer with indentation
   110  	indentedBuffer := new(bytes.Buffer)
   111  	if err := json.Indent(indentedBuffer, bs, "", "\t"); err != nil {
   112  		return nil, err
   113  	}
   114  	return indentedBuffer.Bytes(), nil
   115  }
   116  
   117  func (gs *GenesisSpec) Hash() []byte {
   118  	gsBytes, err := gs.JSONBytes()
   119  	if err != nil {
   120  		panic(fmt.Errorf("could not create hash of GenesisDoc: %v", err))
   121  	}
   122  	hasher := sha256.New()
   123  	hasher.Write(gsBytes)
   124  	return hasher.Sum(nil)
   125  }
   126  
   127  func (gs *GenesisSpec) ShortHash() []byte {
   128  	return gs.Hash()[:genesis.ShortHashSuffixBytes]
   129  }
   130  
   131  func GenesisSpecFromJSON(jsonBlob []byte) (*GenesisSpec, error) {
   132  	genDoc := new(GenesisSpec)
   133  	err := json.Unmarshal(jsonBlob, genDoc)
   134  	if err != nil {
   135  		return nil, fmt.Errorf("couldn't read GenesisSpec: %v", err)
   136  	}
   137  	return genDoc, nil
   138  }
   139  
   140  func accountNameFromIndex(index int) string {
   141  	return fmt.Sprintf("Account_%v", index)
   142  }