mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
620 lines
17 KiB
Go
620 lines
17 KiB
Go
// Copyright (C) 2022, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
package application
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/luxfi/cli/v2/pkg/config"
|
|
"github.com/luxfi/cli/v2/pkg/constants"
|
|
"github.com/luxfi/cli/v2/pkg/key"
|
|
"github.com/luxfi/cli/v2/pkg/lpm"
|
|
"github.com/luxfi/cli/v2/pkg/models"
|
|
"github.com/luxfi/cli/v2/pkg/types"
|
|
"github.com/luxfi/cli/v2/pkg/prompts"
|
|
"github.com/luxfi/ids"
|
|
luxlog "github.com/luxfi/log"
|
|
"github.com/luxfi/geth/core"
|
|
)
|
|
|
|
const (
|
|
WriteReadReadPerms = 0o644
|
|
)
|
|
|
|
type Lux struct {
|
|
Log luxlog.Logger
|
|
baseDir string
|
|
Conf *config.Config
|
|
Prompt prompts.Prompter
|
|
Lpm *lpm.Client
|
|
LpmDir string
|
|
Downloader Downloader
|
|
Apm interface{} // APM client placeholder
|
|
ApmDir string
|
|
}
|
|
|
|
func New() *Lux {
|
|
return &Lux{}
|
|
}
|
|
|
|
func (app *Lux) Setup(baseDir string, log luxlog.Logger, conf *config.Config, prompt prompts.Prompter, downloader Downloader) {
|
|
app.baseDir = baseDir
|
|
app.Log = log
|
|
app.Conf = conf
|
|
app.Prompt = prompt
|
|
app.Downloader = downloader
|
|
}
|
|
|
|
func (app *Lux) GetRunFile() string {
|
|
return filepath.Join(app.GetRunDir(), constants.ServerRunFile)
|
|
}
|
|
|
|
func (app *Lux) GetSnapshotsDir() string {
|
|
return filepath.Join(app.baseDir, constants.SnapshotsDirName)
|
|
}
|
|
|
|
func (app *Lux) GetBaseDir() string {
|
|
return app.baseDir
|
|
}
|
|
|
|
func (app *Lux) GetSubnetDir() string {
|
|
return filepath.Join(app.baseDir, constants.SubnetDir)
|
|
}
|
|
|
|
func (app *Lux) GetReposDir() string {
|
|
return filepath.Join(app.baseDir, constants.ReposDir)
|
|
}
|
|
|
|
func (app *Lux) GetRunDir() string {
|
|
return filepath.Join(app.baseDir, constants.RunDir)
|
|
}
|
|
|
|
func (app *Lux) IsLocalNetworkRunning() bool {
|
|
// Check if the local network is running by checking the gRPC server status
|
|
runFilePath := filepath.Join(app.GetRunDir(), constants.ServerRunFile)
|
|
_, err := os.Stat(runFilePath)
|
|
return err == nil
|
|
}
|
|
|
|
func (app *Lux) GetCustomVMDir() string {
|
|
return filepath.Join(app.baseDir, constants.CustomVMDir)
|
|
}
|
|
|
|
func (app *Lux) GetPluginsDir() string {
|
|
return filepath.Join(app.baseDir, constants.PluginDir)
|
|
}
|
|
|
|
func (app *Lux) GetLuxBinDir() string {
|
|
return filepath.Join(app.baseDir, constants.LuxCliBinDir, constants.LuxInstallDir)
|
|
}
|
|
|
|
func (app *Lux) GetEVMBinDir() string {
|
|
return filepath.Join(app.baseDir, constants.LuxCliBinDir, constants.EVMInstallDir)
|
|
}
|
|
|
|
func (app *Lux) GetUpgradeBytesFilepath(subnetName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), subnetName, constants.UpgradeBytesFileName)
|
|
}
|
|
|
|
func (app *Lux) GetCustomVMPath(subnetName string) string {
|
|
return filepath.Join(app.GetCustomVMDir(), subnetName)
|
|
}
|
|
|
|
func (app *Lux) GetLPMVMPath(vmid string) string {
|
|
return filepath.Join(app.GetLPMPluginDir(), vmid)
|
|
}
|
|
|
|
func (app *Lux) GetGenesisPath(subnetName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), subnetName, constants.GenesisFileName)
|
|
}
|
|
|
|
func (app *Lux) GetSidecarPath(subnetName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), subnetName, constants.SidecarFileName)
|
|
}
|
|
|
|
func (app *Lux) GetConfigPath() string {
|
|
return filepath.Join(app.baseDir, constants.ConfigDir)
|
|
}
|
|
|
|
func (app *Lux) GetElasticSubnetConfigPath(subnetName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), subnetName, constants.ElasticSubnetConfigFileName)
|
|
}
|
|
|
|
func (app *Lux) GetKeyDir() string {
|
|
return filepath.Join(app.baseDir, constants.KeyDir)
|
|
}
|
|
|
|
func (*Lux) GetTmpPluginDir() string {
|
|
return os.TempDir()
|
|
}
|
|
|
|
func (app *Lux) GetLPMBaseDir() string {
|
|
return filepath.Join(app.baseDir, "lpm")
|
|
}
|
|
|
|
func (app *Lux) GetLPMLog() string {
|
|
return filepath.Join(app.baseDir, constants.LogDir, constants.LPMLogName)
|
|
}
|
|
|
|
func (app *Lux) GetLPMPluginDir() string {
|
|
return filepath.Join(app.baseDir, constants.LPMPluginDir)
|
|
}
|
|
|
|
func (app *Lux) GetKeyPath(keyName string) string {
|
|
return filepath.Join(app.baseDir, constants.KeyDir, keyName+constants.KeySuffix)
|
|
}
|
|
|
|
func (app *Lux) GetUpgradeBytesFilePath(subnetName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), subnetName, constants.UpgradeBytesFileName)
|
|
}
|
|
|
|
func (app *Lux) GetDownloader() Downloader {
|
|
return app.Downloader
|
|
}
|
|
|
|
func (*Lux) GetLuxCompatibilityURL() string {
|
|
return constants.LuxCompatibilityURL
|
|
}
|
|
|
|
func (app *Lux) ReadUpgradeFile(subnetName string) ([]byte, error) {
|
|
upgradeBytesFilePath := app.GetUpgradeBytesFilePath(subnetName)
|
|
|
|
return app.readFile(upgradeBytesFilePath)
|
|
}
|
|
|
|
func (app *Lux) ReadLockUpgradeFile(subnetName string) ([]byte, error) {
|
|
upgradeBytesLockFilePath := app.GetUpgradeBytesFilePath(subnetName) + constants.UpgradeBytesLockExtension
|
|
|
|
return app.readFile(upgradeBytesLockFilePath)
|
|
}
|
|
|
|
func (app *Lux) WriteUpgradeFile(subnetName string, bytes []byte) error {
|
|
upgradeBytesFilePath := app.GetUpgradeBytesFilePath(subnetName)
|
|
|
|
return app.writeFile(upgradeBytesFilePath, bytes)
|
|
}
|
|
|
|
func (app *Lux) WriteLockUpgradeFile(subnetName string, bytes []byte) error {
|
|
upgradeBytesLockFilePath := app.GetUpgradeBytesFilePath(subnetName) + constants.UpgradeBytesLockExtension
|
|
|
|
return app.writeFile(upgradeBytesLockFilePath, bytes)
|
|
}
|
|
|
|
func (app *Lux) WriteGenesisFile(subnetName string, genesisBytes []byte) error {
|
|
genesisPath := app.GetGenesisPath(subnetName)
|
|
|
|
return app.writeFile(genesisPath, genesisBytes)
|
|
}
|
|
|
|
func (app *Lux) GenesisExists(subnetName string) bool {
|
|
genesisPath := app.GetGenesisPath(subnetName)
|
|
_, err := os.Stat(genesisPath)
|
|
return err == nil
|
|
}
|
|
|
|
func (app *Lux) SidecarExists(subnetName string) bool {
|
|
sidecarPath := app.GetSidecarPath(subnetName)
|
|
_, err := os.Stat(sidecarPath)
|
|
return err == nil
|
|
}
|
|
|
|
func (app *Lux) SubnetConfigExists(subnetName string) bool {
|
|
// There's always a sidecar, but imported subnets don't have a genesis right now
|
|
return app.SidecarExists(subnetName)
|
|
}
|
|
|
|
func (app *Lux) KeyExists(keyName string) bool {
|
|
keyPath := app.GetKeyPath(keyName)
|
|
_, err := os.Stat(keyPath)
|
|
return err == nil
|
|
}
|
|
|
|
func (app *Lux) CopyGenesisFile(inputFilename string, subnetName string) error {
|
|
genesisBytes, err := os.ReadFile(inputFilename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
genesisPath := app.GetGenesisPath(subnetName)
|
|
if err := os.MkdirAll(filepath.Dir(genesisPath), constants.DefaultPerms755); err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(genesisPath, genesisBytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) CopyVMBinary(inputFilename string, subnetName string) error {
|
|
vmBytes, err := os.ReadFile(inputFilename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
vmPath := app.GetCustomVMPath(subnetName)
|
|
return os.WriteFile(vmPath, vmBytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) CopyKeyFile(inputFilename string, keyName string) error {
|
|
keyBytes, err := os.ReadFile(inputFilename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
keyPath := app.GetKeyPath(keyName)
|
|
return os.WriteFile(keyPath, keyBytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) LoadEvmGenesis(subnetName string) (core.Genesis, error) {
|
|
genesisPath := app.GetGenesisPath(subnetName)
|
|
jsonBytes, err := os.ReadFile(genesisPath)
|
|
if err != nil {
|
|
return core.Genesis{}, err
|
|
}
|
|
|
|
var gen core.Genesis
|
|
err = json.Unmarshal(jsonBytes, &gen)
|
|
return gen, err
|
|
}
|
|
|
|
func (app *Lux) LoadRawGenesis(subnetName string) ([]byte, error) {
|
|
genesisPath := app.GetGenesisPath(subnetName)
|
|
genesisBytes, err := os.ReadFile(genesisPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return genesisBytes, err
|
|
}
|
|
|
|
func (app *Lux) CreateSidecar(sc *models.Sidecar) error {
|
|
if sc.TokenName == "" {
|
|
sc.TokenName = constants.DefaultTokenName
|
|
}
|
|
|
|
sidecarPath := app.GetSidecarPath(sc.Name)
|
|
if err := os.MkdirAll(filepath.Dir(sidecarPath), constants.DefaultPerms755); err != nil {
|
|
return err
|
|
}
|
|
|
|
// only apply the version on a write
|
|
sc.Version = constants.SidecarVersion
|
|
scBytes, err := json.MarshalIndent(sc, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(sidecarPath, scBytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) LoadSidecar(subnetName string) (models.Sidecar, error) {
|
|
sidecarPath := app.GetSidecarPath(subnetName)
|
|
jsonBytes, err := os.ReadFile(sidecarPath)
|
|
if err != nil {
|
|
return models.Sidecar{}, err
|
|
}
|
|
|
|
var sc models.Sidecar
|
|
err = json.Unmarshal(jsonBytes, &sc)
|
|
|
|
if sc.TokenName == "" {
|
|
sc.TokenName = constants.DefaultTokenName
|
|
}
|
|
|
|
return sc, err
|
|
}
|
|
|
|
func (app *Lux) WriteSidecarFile(sc *models.Sidecar) error {
|
|
sidecarPath := app.GetSidecarPath(sc.Name)
|
|
jsonBytes, err := json.MarshalIndent(sc, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return app.writeFile(sidecarPath, jsonBytes)
|
|
}
|
|
|
|
func (app *Lux) UpdateSidecar(sc *models.Sidecar) error {
|
|
sc.Version = constants.SidecarVersion
|
|
scBytes, err := json.MarshalIndent(sc, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sidecarPath := app.GetSidecarPath(sc.Name)
|
|
return os.WriteFile(sidecarPath, scBytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) UpdateSidecarNetworks(
|
|
sc *models.Sidecar,
|
|
network models.Network,
|
|
subnetID ids.ID,
|
|
blockchainID ids.ID,
|
|
) error {
|
|
if sc.Networks == nil {
|
|
sc.Networks = make(map[string]models.NetworkData)
|
|
}
|
|
sc.Networks[network.String()] = models.NetworkData{
|
|
SubnetID: subnetID,
|
|
BlockchainID: blockchainID,
|
|
RPCVersion: sc.RPCVersion,
|
|
}
|
|
if err := app.UpdateSidecar(sc); err != nil {
|
|
return fmt.Errorf("creation of chains and subnet was successful, but failed to update sidecar: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (app *Lux) UpdateSidecarElasticSubnet(
|
|
sc *models.Sidecar,
|
|
network models.Network,
|
|
subnetID ids.ID,
|
|
assetID ids.ID,
|
|
pchainTXID ids.ID,
|
|
tokenName string,
|
|
tokenSymbol string,
|
|
) error {
|
|
if sc.ElasticSubnet == nil {
|
|
sc.ElasticSubnet = make(map[string]models.ElasticSubnet)
|
|
}
|
|
partialTxs := sc.ElasticSubnet[network.String()].Txs
|
|
sc.ElasticSubnet[network.String()] = models.ElasticSubnet{
|
|
SubnetID: subnetID,
|
|
AssetID: assetID,
|
|
PChainTXID: pchainTXID,
|
|
TokenName: tokenName,
|
|
TokenSymbol: tokenSymbol,
|
|
Txs: partialTxs,
|
|
}
|
|
if err := app.UpdateSidecar(sc); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (app *Lux) UpdateSidecarPermissionlessValidator(
|
|
sc *models.Sidecar,
|
|
network models.Network,
|
|
nodeID string,
|
|
txID ids.ID,
|
|
) error {
|
|
elasticSubnet := sc.ElasticSubnet[network.String()]
|
|
if elasticSubnet.Validators == nil {
|
|
elasticSubnet.Validators = make(map[string]models.PermissionlessValidators)
|
|
}
|
|
elasticSubnet.Validators[nodeID] = models.PermissionlessValidators{TxID: txID}
|
|
sc.ElasticSubnet[network.String()] = elasticSubnet
|
|
if err := app.UpdateSidecar(sc); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (app *Lux) UpdateSidecarElasticSubnetPartialTx(
|
|
sc *models.Sidecar,
|
|
network models.Network,
|
|
txName string,
|
|
txID ids.ID,
|
|
) error {
|
|
if sc.ElasticSubnet == nil {
|
|
sc.ElasticSubnet = make(map[string]models.ElasticSubnet)
|
|
}
|
|
partialTxs := make(map[string]ids.ID)
|
|
if sc.ElasticSubnet[network.String()].Txs != nil {
|
|
partialTxs = sc.ElasticSubnet[network.String()].Txs
|
|
}
|
|
partialTxs[txName] = txID
|
|
sc.ElasticSubnet[network.String()] = models.ElasticSubnet{
|
|
Txs: partialTxs,
|
|
}
|
|
return app.UpdateSidecar(sc)
|
|
}
|
|
|
|
func (app *Lux) GetTokenName(subnetName string) string {
|
|
sidecar, err := app.LoadSidecar(subnetName)
|
|
if err != nil {
|
|
return constants.DefaultTokenName
|
|
}
|
|
return sidecar.TokenName
|
|
}
|
|
|
|
func (app *Lux) GetSidecarNames() ([]string, error) {
|
|
matches, err := os.ReadDir(app.GetSubnetDir())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var names []string
|
|
for _, m := range matches {
|
|
if !m.IsDir() {
|
|
continue
|
|
}
|
|
// a subnet dir could theoretically exist without a sidecar yet...
|
|
if _, err := os.Stat(filepath.Join(app.GetSubnetDir(), m.Name(), constants.SidecarFileName)); err == nil {
|
|
names = append(names, m.Name())
|
|
}
|
|
}
|
|
return names, nil
|
|
}
|
|
|
|
func (*Lux) readFile(path string) ([]byte, error) {
|
|
if err := os.MkdirAll(filepath.Dir(path), constants.DefaultPerms755); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return os.ReadFile(path)
|
|
}
|
|
|
|
func (*Lux) writeFile(path string, bytes []byte) error {
|
|
if err := os.MkdirAll(filepath.Dir(path), constants.DefaultPerms755); err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(path, bytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) LoadConfig() (types.Config, error) {
|
|
configPath := app.GetConfigPath()
|
|
jsonBytes, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return types.Config{}, err
|
|
}
|
|
|
|
var cfg types.Config
|
|
err = json.Unmarshal(jsonBytes, &cfg)
|
|
return cfg, err
|
|
}
|
|
|
|
func (app *Lux) ConfigFileExists() bool {
|
|
configPath := app.GetConfigPath()
|
|
_, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// CaptureYesNo delegates to the internal prompt
|
|
func (app *Lux) CaptureYesNo(prompt string) (bool, error) {
|
|
return app.Prompt.CaptureYesNo(prompt)
|
|
}
|
|
|
|
func (app *Lux) WriteConfigFile(bytes []byte) error {
|
|
configPath := app.GetConfigPath()
|
|
return app.writeFile(configPath, bytes)
|
|
}
|
|
|
|
func (app *Lux) CreateElasticSubnetConfig(subnetName string, es *models.ElasticSubnetConfig) error {
|
|
elasticSubetConfigPath := app.GetElasticSubnetConfigPath(subnetName)
|
|
if err := os.MkdirAll(filepath.Dir(elasticSubetConfigPath), constants.DefaultPerms755); err != nil {
|
|
return err
|
|
}
|
|
|
|
esBytes, err := json.MarshalIndent(es, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(elasticSubetConfigPath, esBytes, WriteReadReadPerms)
|
|
}
|
|
|
|
func (app *Lux) LoadElasticSubnetConfig(subnetName string) (models.ElasticSubnetConfig, error) {
|
|
elasticSubnetConfigPath := app.GetElasticSubnetConfigPath(subnetName)
|
|
jsonBytes, err := os.ReadFile(elasticSubnetConfigPath)
|
|
if err != nil {
|
|
return models.ElasticSubnetConfig{}, err
|
|
}
|
|
|
|
var esc models.ElasticSubnetConfig
|
|
err = json.Unmarshal(jsonBytes, &esc)
|
|
|
|
return esc, err
|
|
}
|
|
|
|
// GetKeyPaths returns all key file paths in the key directory
|
|
func (app *Lux) GetKeyPaths() ([]string, error) {
|
|
keyDir := app.GetKeyDir()
|
|
files, err := os.ReadDir(keyDir)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return []string{}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var keyPaths []string
|
|
for _, file := range files {
|
|
if !file.IsDir() && strings.HasSuffix(file.Name(), constants.KeySuffix) {
|
|
keyPaths = append(keyPaths, filepath.Join(keyDir, file.Name()))
|
|
}
|
|
}
|
|
return keyPaths, nil
|
|
}
|
|
|
|
// GetKey loads a key by name from the key directory
|
|
func (app *Lux) GetKey(keyName string, network models.Network, createIfMissing bool) (*key.SoftKey, error) {
|
|
// This is a placeholder implementation
|
|
// In real implementation, this would load the key from disk
|
|
return nil, fmt.Errorf("GetKey not implemented")
|
|
}
|
|
|
|
// GetBlockchainNames returns all blockchain names from the subnet directory
|
|
func (app *Lux) GetBlockchainNames() ([]string, error) {
|
|
subnetDir := app.GetSubnetDir()
|
|
files, err := os.ReadDir(subnetDir)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return []string{}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var names []string
|
|
for _, file := range files {
|
|
if file.IsDir() {
|
|
// Check if it has a sidecar file to confirm it's a blockchain
|
|
sidecarPath := filepath.Join(subnetDir, file.Name(), constants.SidecarFileName)
|
|
if _, err := os.Stat(sidecarPath); err == nil {
|
|
names = append(names, file.Name())
|
|
}
|
|
}
|
|
}
|
|
return names, nil
|
|
}
|
|
|
|
// GetSignatureAggregatorBinDir returns the directory for signature aggregator binaries
|
|
func (app *Lux) GetSignatureAggregatorBinDir() string {
|
|
return filepath.Join(app.baseDir, constants.LuxCliBinDir, constants.SignatureAggregator)
|
|
}
|
|
|
|
// ChainConfigExists checks if a chain config file exists for the given blockchain
|
|
func (app *Lux) ChainConfigExists(blockchainName string) bool {
|
|
configPath := app.GetChainConfigPath(blockchainName)
|
|
_, err := os.Stat(configPath)
|
|
return err == nil
|
|
}
|
|
|
|
// GetChainConfigPath returns the path to the chain config file for a blockchain
|
|
func (app *Lux) GetChainConfigPath(blockchainName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), blockchainName, constants.ChainConfigDir, constants.ChainConfigFileName)
|
|
}
|
|
|
|
// NetworkUpgradeExists checks if a network upgrade file exists for the given blockchain
|
|
func (app *Lux) NetworkUpgradeExists(blockchainName string) bool {
|
|
upgradePath := app.GetUpgradeBytesFilepath(blockchainName)
|
|
_, err := os.Stat(upgradePath)
|
|
return err == nil
|
|
}
|
|
|
|
// LuxdSubnetConfigExists checks if a luxd subnet config file exists for the given blockchain
|
|
func (app *Lux) LuxdSubnetConfigExists(blockchainName string) bool {
|
|
configPath := app.GetLuxdSubnetConfigPath(blockchainName)
|
|
_, err := os.Stat(configPath)
|
|
return err == nil
|
|
}
|
|
|
|
// GetLuxdSubnetConfigPath returns the path to the luxd subnet config file for a blockchain
|
|
func (app *Lux) GetLuxdSubnetConfigPath(blockchainName string) string {
|
|
return filepath.Join(app.GetSubnetDir(), blockchainName, constants.SubnetConfigFileName)
|
|
}
|
|
|
|
// GetPerNodeBlockchainConfig returns per-node blockchain configuration for the given blockchain
|
|
func (app *Lux) GetPerNodeBlockchainConfig(blockchainName string) (map[string]interface{}, error) {
|
|
perNodeConfigPath := filepath.Join(app.GetSubnetDir(), blockchainName, constants.PerNodeChainConfigFileName)
|
|
if _, err := os.Stat(perNodeConfigPath); os.IsNotExist(err) {
|
|
return nil, nil
|
|
}
|
|
|
|
configBytes, err := os.ReadFile(perNodeConfigPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var config map[string]interface{}
|
|
if err := json.Unmarshal(configBytes, &config); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return config, nil
|
|
}
|