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  }