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 }