package state import ( "io/ioutil" "os" "time" "github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/common" dbm "github.com/tendermint/tendermint/db" "github.com/tendermint/tendermint/merkle" ptypes "github.com/tendermint/tendermint/permission/types" "github.com/tendermint/tendermint/types" ) //------------------------------------------------------------ // we store the gendoc in the db var GenDocKey = []byte("GenDocKey") //------------------------------------------------------------ // core types for a genesis definition type BasicAccount struct { Address []byte `json:"address"` Amount int64 `json:"amount"` } type GenesisAccount struct { Address []byte `json:"address"` Amount int64 `json:"amount"` Name string `json:"name"` Permissions *ptypes.AccountPermissions `json:"permissions"` } type GenesisValidator struct { PubKey account.PubKeyEd25519 `json:"pub_key"` Amount int64 `json:"amount"` Name string `json:"name"` UnbondTo []BasicAccount `json:"unbond_to"` } type GenesisParams struct { GlobalPermissions *ptypes.AccountPermissions `json:"global_permissions"` } type GenesisDoc struct { GenesisTime time.Time `json:"genesis_time"` ChainID string `json:"chain_id"` Params *GenesisParams `json:"params"` Accounts []GenesisAccount `json:"accounts"` Validators []GenesisValidator `json:"validators"` } //------------------------------------------------------------ // Make genesis state from file func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) { var err error binary.ReadJSON(&genState, jsonBlob, &err) if err != nil { log.Error(Fmt("Couldn't read GenesisDoc: %v", err)) os.Exit(1) } return } func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) (*GenesisDoc, *State) { jsonBlob, err := ioutil.ReadFile(genDocFile) if err != nil { log.Error(Fmt("Couldn't read GenesisDoc file: %v", err)) os.Exit(1) } genDoc := GenesisDocFromJSON(jsonBlob) return genDoc, MakeGenesisState(db, genDoc) } func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State { if len(genDoc.Validators) == 0 { Exit(Fmt("The genesis file has no validators")) } if genDoc.GenesisTime.IsZero() { genDoc.GenesisTime = time.Now() } // Make accounts state tree accounts := merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db) for _, genAcc := range genDoc.Accounts { perm := ptypes.ZeroAccountPermissions if genAcc.Permissions != nil { perm = *genAcc.Permissions } acc := &account.Account{ Address: genAcc.Address, PubKey: nil, Sequence: 0, Balance: genAcc.Amount, Permissions: perm, } accounts.Set(acc.Address, acc) } // global permissions are saved as the 0 address // so they are included in the accounts tree globalPerms := ptypes.DefaultAccountPermissions if genDoc.Params != nil && genDoc.Params.GlobalPermissions != nil { globalPerms = *genDoc.Params.GlobalPermissions // XXX: make sure the set bits are all true // Without it the HasPermission() functions will fail globalPerms.Base.SetBit = ptypes.AllPermFlags } permsAcc := &account.Account{ Address: ptypes.GlobalPermissionsAddress, PubKey: nil, Sequence: 0, Balance: 1337, Permissions: globalPerms, } accounts.Set(permsAcc.Address, permsAcc) // Make validatorInfos state tree && validators slice validatorInfos := merkle.NewIAVLTree(binary.BasicCodec, ValidatorInfoCodec, 0, db) validators := make([]*Validator, len(genDoc.Validators)) for i, val := range genDoc.Validators { pubKey := val.PubKey address := pubKey.Address() // Make ValidatorInfo valInfo := &ValidatorInfo{ Address: address, PubKey: pubKey, UnbondTo: make([]*types.TxOutput, len(val.UnbondTo)), FirstBondHeight: 0, FirstBondAmount: val.Amount, } for i, unbondTo := range val.UnbondTo { valInfo.UnbondTo[i] = &types.TxOutput{ Address: unbondTo.Address, Amount: unbondTo.Amount, } } validatorInfos.Set(address, valInfo) // Make validator validators[i] = &Validator{ Address: address, PubKey: pubKey, VotingPower: val.Amount, } } // Make namereg tree nameReg := merkle.NewIAVLTree(binary.BasicCodec, NameRegCodec, 0, db) // TODO: add names to genesis.json // IAVLTrees must be persisted before copy operations. accounts.Save() validatorInfos.Save() nameReg.Save() return &State{ DB: db, ChainID: genDoc.ChainID, LastBlockHeight: 0, LastBlockHash: nil, LastBlockParts: types.PartSetHeader{}, LastBlockTime: genDoc.GenesisTime, BondedValidators: NewValidatorSet(validators), LastBondedValidators: NewValidatorSet(nil), UnbondingValidators: NewValidatorSet(nil), accounts: accounts, validatorInfos: validatorInfos, nameReg: nameReg, } }