github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/genutil/collect.go (about) 1 package genutil 2 3 // DONTCOVER 4 5 import ( 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "sort" 13 "strings" 14 15 cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config" 16 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 17 18 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec" 19 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 20 authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported" 21 authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types" 22 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/genutil/types" 23 stakingtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/types" 24 ) 25 26 // GenAppStateFromConfig gets the genesis app state from the config 27 func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, 28 initCfg InitConfig, genDoc tmtypes.GenesisDoc, 29 genAccIterator types.GenesisAccountsIterator, 30 ) (appState json.RawMessage, err error) { 31 32 // process genesis transactions, else create default genesis.json 33 appGenTxs, persistentPeers, err := CollectStdTxs( 34 cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genAccIterator) 35 if err != nil { 36 return appState, err 37 } 38 39 config.P2P.PersistentPeers = persistentPeers 40 cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config) 41 42 // if there are no gen txs to be processed, return the default empty state 43 if len(appGenTxs) == 0 { 44 return appState, errors.New("there must be at least one genesis tx") 45 } 46 47 // create the app state 48 appGenesisState, err := GenesisStateFromGenDoc(cdc, genDoc) 49 if err != nil { 50 return appState, err 51 } 52 53 appGenesisState, err = SetGenTxsInAppGenesisState(cdc, appGenesisState, appGenTxs) 54 if err != nil { 55 return appState, err 56 } 57 appState, err = codec.MarshalJSONIndent(cdc, appGenesisState) 58 if err != nil { 59 return appState, err 60 } 61 62 genDoc.AppState = appState 63 err = ExportGenesisFile(&genDoc, config.GenesisFile()) 64 return appState, err 65 } 66 67 // CollectStdTxs processes and validates application's genesis StdTxs and returns 68 // the list of appGenTxs, and persistent peers required to generate genesis.json. 69 func CollectStdTxs(cdc *codec.Codec, moniker, genTxsDir string, 70 genDoc tmtypes.GenesisDoc, genAccIterator types.GenesisAccountsIterator, 71 ) (appGenTxs []authtypes.StdTx, persistentPeers string, err error) { 72 73 var fos []os.FileInfo 74 fos, err = ioutil.ReadDir(genTxsDir) 75 if err != nil { 76 return appGenTxs, persistentPeers, err 77 } 78 79 // prepare a map of all accounts in genesis state to then validate 80 // against the validators addresses 81 var appState map[string]json.RawMessage 82 if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil { 83 return appGenTxs, persistentPeers, err 84 } 85 86 addrMap := make(map[string]authexported.Account) 87 genAccIterator.IterateGenesisAccounts(cdc, appState, 88 func(acc authexported.Account) (stop bool) { 89 addrMap[acc.GetAddress().String()] = acc 90 return false 91 }, 92 ) 93 94 // addresses and IPs (and port) validator server info 95 var addressesIPs []string 96 97 for _, fo := range fos { 98 filename := filepath.Join(genTxsDir, fo.Name()) 99 if !fo.IsDir() && (filepath.Ext(filename) != ".json") { 100 continue 101 } 102 103 // get the genStdTx 104 var jsonRawTx []byte 105 if jsonRawTx, err = ioutil.ReadFile(filename); err != nil { 106 return appGenTxs, persistentPeers, err 107 } 108 var genStdTx authtypes.StdTx 109 if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil { 110 return appGenTxs, persistentPeers, err 111 } 112 appGenTxs = append(appGenTxs, genStdTx) 113 114 // the memo flag is used to store 115 // the ip and node-id, for example this may be: 116 // "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656" 117 nodeAddrIP := genStdTx.GetMemo() 118 if len(nodeAddrIP) == 0 { 119 return appGenTxs, persistentPeers, fmt.Errorf( 120 "couldn't find node's address and IP in %s", fo.Name()) 121 } 122 123 // genesis transactions must be single-message 124 msgs := genStdTx.GetMsgs() 125 if len(msgs) != 1 { 126 return appGenTxs, persistentPeers, errors.New( 127 "each genesis transaction must provide a single genesis message") 128 } 129 130 // TODO abstract out staking message validation back to staking 131 msg := msgs[0].(stakingtypes.MsgCreateValidator) 132 // validate delegator and validator addresses and funds against the accounts in the state 133 delAddr := msg.DelegatorAddress.String() 134 valAddr := sdk.AccAddress(msg.ValidatorAddress).String() 135 136 delAcc, delOk := addrMap[delAddr] 137 if !delOk { 138 return appGenTxs, persistentPeers, fmt.Errorf( 139 "account %v not in genesis.json: %+v", delAddr, addrMap) 140 } 141 142 _, valOk := addrMap[valAddr] 143 if !valOk { 144 return appGenTxs, persistentPeers, fmt.Errorf( 145 "account %v not in genesis.json: %+v", valAddr, addrMap) 146 } 147 148 if delAcc.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) { 149 return appGenTxs, persistentPeers, fmt.Errorf( 150 "insufficient fund for delegation %v: %v < %v", 151 delAcc.GetAddress(), delAcc.GetCoins().AmountOf(msg.Value.Denom), msg.Value.Amount, 152 ) 153 } 154 155 // exclude itself from persistent peers 156 if msg.Description.Moniker != moniker { 157 addressesIPs = append(addressesIPs, nodeAddrIP) 158 } 159 } 160 161 sort.Strings(addressesIPs) 162 persistentPeers = strings.Join(addressesIPs, ",") 163 164 return appGenTxs, persistentPeers, nil 165 }