github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/types/genesis.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sort" 7 8 proto "github.com/cosmos/gogoproto/proto" 9 10 "github.com/cosmos/cosmos-sdk/codec" 11 "github.com/cosmos/cosmos-sdk/codec/types" 12 sdk "github.com/cosmos/cosmos-sdk/types" 13 "github.com/cosmos/cosmos-sdk/types/module" 14 ) 15 16 var _ types.UnpackInterfacesMessage = GenesisState{} 17 18 // RandomGenesisAccountsFn defines the function required to generate custom account types 19 type RandomGenesisAccountsFn func(simState *module.SimulationState) GenesisAccounts 20 21 // NewGenesisState - Create a new genesis state 22 func NewGenesisState(params Params, accounts GenesisAccounts) *GenesisState { 23 genAccounts, err := PackAccounts(accounts) 24 if err != nil { 25 panic(err) 26 } 27 return &GenesisState{ 28 Params: params, 29 Accounts: genAccounts, 30 } 31 } 32 33 // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces 34 func (g GenesisState) UnpackInterfaces(unpacker types.AnyUnpacker) error { 35 for _, any := range g.Accounts { 36 var account GenesisAccount 37 err := unpacker.UnpackAny(any, &account) 38 if err != nil { 39 return err 40 } 41 } 42 return nil 43 } 44 45 // DefaultGenesisState - Return a default genesis state 46 func DefaultGenesisState() *GenesisState { 47 return NewGenesisState(DefaultParams(), GenesisAccounts{}) 48 } 49 50 // GetGenesisStateFromAppState returns x/auth GenesisState given raw application 51 // genesis state. 52 func GetGenesisStateFromAppState(cdc codec.Codec, appState map[string]json.RawMessage) GenesisState { 53 var genesisState GenesisState 54 55 if appState[ModuleName] != nil { 56 cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState) 57 } 58 59 return genesisState 60 } 61 62 // ValidateGenesis performs basic validation of auth genesis data returning an 63 // error for any failed validation criteria. 64 func ValidateGenesis(data GenesisState) error { 65 if err := data.Params.Validate(); err != nil { 66 return err 67 } 68 69 genAccs, err := UnpackAccounts(data.Accounts) 70 if err != nil { 71 return err 72 } 73 74 return ValidateGenAccounts(genAccs) 75 } 76 77 // SanitizeGenesisAccounts sorts accounts and coin sets. 78 func SanitizeGenesisAccounts(genAccs GenesisAccounts) GenesisAccounts { 79 // Make sure there aren't any duplicated account numbers by fixing the duplicates with the lowest unused values. 80 // seenAccNum = easy lookup for used account numbers. 81 seenAccNum := map[uint64]bool{} 82 // dupAccNum = a map of account number to accounts with duplicate account numbers (excluding the 1st one seen). 83 dupAccNum := map[uint64]GenesisAccounts{} 84 for _, acc := range genAccs { 85 num := acc.GetAccountNumber() 86 if !seenAccNum[num] { 87 seenAccNum[num] = true 88 } else { 89 dupAccNum[num] = append(dupAccNum[num], acc) 90 } 91 } 92 93 // dupAccNums a sorted list of the account numbers with duplicates. 94 var dupAccNums []uint64 95 for num := range dupAccNum { 96 dupAccNums = append(dupAccNums, num) 97 } 98 sort.Slice(dupAccNums, func(i, j int) bool { 99 return dupAccNums[i] < dupAccNums[j] 100 }) 101 102 // Change the account number of the duplicated ones to the first unused value. 103 globalNum := uint64(0) 104 for _, dupNum := range dupAccNums { 105 accs := dupAccNum[dupNum] 106 for _, acc := range accs { 107 for seenAccNum[globalNum] { 108 globalNum++ 109 } 110 if err := acc.SetAccountNumber(globalNum); err != nil { 111 panic(err) 112 } 113 seenAccNum[globalNum] = true 114 } 115 } 116 117 // Then sort them all by account number. 118 sort.Slice(genAccs, func(i, j int) bool { 119 return genAccs[i].GetAccountNumber() < genAccs[j].GetAccountNumber() 120 }) 121 return genAccs 122 } 123 124 // ValidateGenAccounts validates an array of GenesisAccounts and checks for duplicates 125 func ValidateGenAccounts(accounts GenesisAccounts) error { 126 addrMap := make(map[string]bool, len(accounts)) 127 128 for _, acc := range accounts { 129 // check for duplicated accounts 130 addrStr := acc.GetAddress().String() 131 if _, ok := addrMap[addrStr]; ok { 132 return fmt.Errorf("duplicate account found in genesis state; address: %s", addrStr) 133 } 134 135 addrMap[addrStr] = true 136 137 // check account specific validation 138 if err := acc.Validate(); err != nil { 139 return fmt.Errorf("invalid account found in genesis state; address: %s, error: %s", addrStr, err.Error()) 140 } 141 } 142 return nil 143 } 144 145 // GenesisAccountIterator implements genesis account iteration. 146 type GenesisAccountIterator struct{} 147 148 // IterateGenesisAccounts iterates over all the genesis accounts found in 149 // appGenesis and invokes a callback on each genesis account. If any call 150 // returns true, iteration stops. 151 func (GenesisAccountIterator) IterateGenesisAccounts( 152 cdc codec.Codec, appGenesis map[string]json.RawMessage, cb func(sdk.AccountI) (stop bool), 153 ) { 154 for _, genAcc := range GetGenesisStateFromAppState(cdc, appGenesis).Accounts { 155 acc, ok := genAcc.GetCachedValue().(sdk.AccountI) 156 if !ok { 157 panic("expected account") 158 } 159 if cb(acc) { 160 break 161 } 162 } 163 } 164 165 // PackAccounts converts GenesisAccounts to Any slice 166 func PackAccounts(accounts GenesisAccounts) ([]*types.Any, error) { 167 accountsAny := make([]*types.Any, len(accounts)) 168 for i, acc := range accounts { 169 msg, ok := acc.(proto.Message) 170 if !ok { 171 return nil, fmt.Errorf("cannot proto marshal %T", acc) 172 } 173 any, err := types.NewAnyWithValue(msg) 174 if err != nil { 175 return nil, err 176 } 177 accountsAny[i] = any 178 } 179 180 return accountsAny, nil 181 } 182 183 // UnpackAccounts converts Any slice to GenesisAccounts 184 func UnpackAccounts(accountsAny []*types.Any) (GenesisAccounts, error) { 185 accounts := make(GenesisAccounts, len(accountsAny)) 186 for i, any := range accountsAny { 187 acc, ok := any.GetCachedValue().(GenesisAccount) 188 if !ok { 189 return nil, fmt.Errorf("expected genesis account") 190 } 191 accounts[i] = acc 192 } 193 194 return accounts, nil 195 }