github.com/MetalBlockchain/metalgo@v1.11.9/tests/fixture/tmpnet/network_config.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package tmpnet 5 6 import ( 7 "encoding/json" 8 "errors" 9 "fmt" 10 "os" 11 "path/filepath" 12 13 "github.com/MetalBlockchain/metalgo/genesis" 14 "github.com/MetalBlockchain/metalgo/utils/crypto/secp256k1" 15 "github.com/MetalBlockchain/metalgo/utils/perms" 16 ) 17 18 // The Network type is defined in this file (reading/writing configuration) and network.go 19 // (orchestration). 20 21 var errMissingNetworkDir = errors.New("failed to write network: missing network directory") 22 23 // Read network and node configuration from disk. 24 func (n *Network) Read() error { 25 if err := n.readNetwork(); err != nil { 26 return err 27 } 28 if err := n.readNodes(); err != nil { 29 return err 30 } 31 return n.readSubnets() 32 } 33 34 // Write network configuration to disk. 35 func (n *Network) Write() error { 36 if len(n.Dir) == 0 { 37 return errMissingNetworkDir 38 } 39 if err := n.writeGenesis(); err != nil { 40 return err 41 } 42 if err := n.writeChainConfigs(); err != nil { 43 return err 44 } 45 if err := n.writeNetworkConfig(); err != nil { 46 return err 47 } 48 if err := n.writeEnvFile(); err != nil { 49 return err 50 } 51 return n.writeNodes() 52 } 53 54 // Read network configuration from disk. 55 func (n *Network) readNetwork() error { 56 if err := n.readGenesis(); err != nil { 57 return err 58 } 59 if err := n.readChainConfigs(); err != nil { 60 return err 61 } 62 return n.readConfig() 63 } 64 65 // Read the non-ephemeral nodes associated with the network from disk. 66 func (n *Network) readNodes() error { 67 nodes, err := ReadNodes(n.Dir, false /* includeEphemeral */) 68 if err != nil { 69 return err 70 } 71 n.Nodes = nodes 72 return nil 73 } 74 75 func (n *Network) writeNodes() error { 76 for _, node := range n.Nodes { 77 if err := node.Write(); err != nil { 78 return err 79 } 80 } 81 return nil 82 } 83 84 func (n *Network) getGenesisPath() string { 85 return filepath.Join(n.Dir, "genesis.json") 86 } 87 88 func (n *Network) readGenesis() error { 89 bytes, err := os.ReadFile(n.getGenesisPath()) 90 if err != nil { 91 return fmt.Errorf("failed to read genesis: %w", err) 92 } 93 genesis := genesis.UnparsedConfig{} 94 if err := json.Unmarshal(bytes, &genesis); err != nil { 95 return fmt.Errorf("failed to unmarshal genesis: %w", err) 96 } 97 n.Genesis = &genesis 98 return nil 99 } 100 101 func (n *Network) writeGenesis() error { 102 bytes, err := DefaultJSONMarshal(n.Genesis) 103 if err != nil { 104 return fmt.Errorf("failed to marshal genesis: %w", err) 105 } 106 if err := os.WriteFile(n.getGenesisPath(), bytes, perms.ReadWrite); err != nil { 107 return fmt.Errorf("failed to write genesis: %w", err) 108 } 109 return nil 110 } 111 112 func (n *Network) getChainConfigDir() string { 113 return filepath.Join(n.Dir, "chains") 114 } 115 116 func (n *Network) readChainConfigs() error { 117 baseChainConfigDir := n.getChainConfigDir() 118 entries, err := os.ReadDir(baseChainConfigDir) 119 if err != nil { 120 return fmt.Errorf("failed to read chain config dir: %w", err) 121 } 122 123 // Clear the map of data that may end up stale (e.g. if a given 124 // chain is in the map but no longer exists on disk) 125 n.ChainConfigs = map[string]FlagsMap{} 126 127 for _, entry := range entries { 128 if !entry.IsDir() { 129 // Chain config files are expected to be nested under a 130 // directory with the name of the chain alias. 131 continue 132 } 133 chainAlias := entry.Name() 134 configPath := filepath.Join(baseChainConfigDir, chainAlias, defaultConfigFilename) 135 if _, err := os.Stat(configPath); os.IsNotExist(err) { 136 // No config file present 137 continue 138 } 139 chainConfig, err := ReadFlagsMap(configPath, chainAlias+" chain config") 140 if err != nil { 141 return err 142 } 143 n.ChainConfigs[chainAlias] = chainConfig 144 } 145 146 return nil 147 } 148 149 func (n *Network) writeChainConfigs() error { 150 baseChainConfigDir := n.getChainConfigDir() 151 152 for chainAlias, chainConfig := range n.ChainConfigs { 153 // Create the directory 154 chainConfigDir := filepath.Join(baseChainConfigDir, chainAlias) 155 if err := os.MkdirAll(chainConfigDir, perms.ReadWriteExecute); err != nil { 156 return fmt.Errorf("failed to create %s chain config dir: %w", chainAlias, err) 157 } 158 159 // Write the file 160 path := filepath.Join(chainConfigDir, defaultConfigFilename) 161 if err := chainConfig.Write(path, chainAlias+" chain config"); err != nil { 162 return err 163 } 164 } 165 166 // TODO(marun) Ensure the removal of chain aliases that aren't present in the map 167 168 return nil 169 } 170 171 func (n *Network) getConfigPath() string { 172 return filepath.Join(n.Dir, defaultConfigFilename) 173 } 174 175 func (n *Network) readConfig() error { 176 bytes, err := os.ReadFile(n.getConfigPath()) 177 if err != nil { 178 return fmt.Errorf("failed to read network config: %w", err) 179 } 180 if err := json.Unmarshal(bytes, n); err != nil { 181 return fmt.Errorf("failed to unmarshal network config: %w", err) 182 } 183 return nil 184 } 185 186 // The subset of network fields to store in the network config file. 187 type serializedNetworkConfig struct { 188 UUID string 189 Owner string 190 DefaultFlags FlagsMap 191 DefaultRuntimeConfig NodeRuntimeConfig 192 PreFundedKeys []*secp256k1.PrivateKey 193 } 194 195 func (n *Network) writeNetworkConfig() error { 196 config := &serializedNetworkConfig{ 197 UUID: n.UUID, 198 Owner: n.Owner, 199 DefaultFlags: n.DefaultFlags, 200 DefaultRuntimeConfig: n.DefaultRuntimeConfig, 201 PreFundedKeys: n.PreFundedKeys, 202 } 203 bytes, err := DefaultJSONMarshal(config) 204 if err != nil { 205 return fmt.Errorf("failed to marshal network config: %w", err) 206 } 207 if err := os.WriteFile(n.getConfigPath(), bytes, perms.ReadWrite); err != nil { 208 return fmt.Errorf("failed to write network config: %w", err) 209 } 210 return nil 211 } 212 213 func (n *Network) EnvFilePath() string { 214 return filepath.Join(n.Dir, "network.env") 215 } 216 217 func (n *Network) EnvFileContents() string { 218 return fmt.Sprintf("export %s=%s", NetworkDirEnvName, n.Dir) 219 } 220 221 // Write an env file that sets the network dir env when sourced. 222 func (n *Network) writeEnvFile() error { 223 if err := os.WriteFile(n.EnvFilePath(), []byte(n.EnvFileContents()), perms.ReadWrite); err != nil { 224 return fmt.Errorf("failed to write network env file: %w", err) 225 } 226 return nil 227 } 228 229 func (n *Network) getSubnetDir() string { 230 return filepath.Join(n.Dir, defaultSubnetDirName) 231 } 232 233 func (n *Network) readSubnets() error { 234 subnets, err := readSubnets(n.getSubnetDir()) 235 if err != nil { 236 return err 237 } 238 n.Subnets = subnets 239 return nil 240 }