ceremonyclient/client/utils/node.go
2025-04-26 13:22:55 -08:00

238 lines
6.5 KiB
Go

package utils
import (
"encoding/hex"
"fmt"
"os"
"os/exec"
"path/filepath"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/pkg/errors"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"source.quilibrium.com/quilibrium/monorepo/node/config"
)
var (
DefaultNodeConfigName = "node-quickstart"
NodeDataPath = filepath.Join(BinaryPath, string(ReleaseTypeNode))
NodeEnvPath = filepath.Join(RootQuilibriumPath, "quilibrium.env")
NodeServiceName = "quilibrium-node"
DefaultNodeSymlinkPath = filepath.Join(DefaultSymlinkDir, NodeServiceName)
LogPath = "/var/log/quilibrium"
)
func GetPeerIDFromConfig(cfg *config.Config) peer.ID {
peerPrivKey, err := hex.DecodeString(cfg.P2P.PeerPrivKey)
if err != nil {
panic(errors.Wrap(err, "error unmarshaling peerkey"))
}
privKey, err := crypto.UnmarshalEd448PrivateKey(peerPrivKey)
if err != nil {
panic(errors.Wrap(err, "error unmarshaling peerkey"))
}
pub := privKey.GetPublic()
id, err := peer.IDFromPublicKey(pub)
if err != nil {
panic(errors.Wrap(err, "error getting peer id"))
}
return id
}
func GetPrivKeyFromConfig(cfg *config.Config) (crypto.PrivKey, error) {
peerPrivKey, err := hex.DecodeString(cfg.P2P.PeerPrivKey)
if err != nil {
panic(errors.Wrap(err, "error unmarshaling peerkey"))
}
privKey, err := crypto.UnmarshalEd448PrivateKey(peerPrivKey)
return privKey, err
}
func IsExistingNodeVersion(version string) bool {
return FileExists(filepath.Join(NodeDataPath, version))
}
func CheckForSystemd() bool {
// Check if systemctl command exists
_, err := exec.LookPath("systemctl")
return err == nil
}
func GetNodeConfigHomeDir() string {
userLookup, err := GetCurrentSudoUser()
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting current user: %v\n", err)
os.Exit(1)
}
path := filepath.Join(userLookup.HomeDir, ".quilibrium", "configs")
if _, err := os.Stat(path); os.IsNotExist(err) {
ValidateAndCreateDir(path, userLookup)
}
return path
}
func GetDefaultNodeConfigDir() (string, error) {
configPath := filepath.Join(GetNodeConfigHomeDir(), DefaultNodeConfigName)
if _, err := os.Stat(configPath); os.IsNotExist(err) {
// if it doesn't exist
// check if the .config directory exists in the current working directory
altConfigPath := filepath.Join(".", ".config")
if _, err := os.Stat(altConfigPath); !os.IsNotExist(err) {
return altConfigPath, nil
}
fmt.Printf("Default node config directory does not exist, creating it\n")
// if neither exists, create it
CreateDefaultNodeConfig(DefaultNodeConfigName)
return configPath, nil
}
// Check if the config path is a symlink
realPath, err := filepath.EvalSymlinks(configPath)
if err != nil {
// If there's an error evaluating symlinks, return the original path
return configPath, err
}
// If it is a symlink, return the real path
return realPath, nil
}
func LoadDefaultNodeConfig() (*config.Config, error) {
// check for the symlinked default config
configDir, err := GetDefaultNodeConfigDir()
if err != nil {
return nil, err
}
return config.LoadConfig(configDir, "", false)
}
func LoadNodeConfig(configDirectory string) (*config.Config, error) {
// if the provided config directory is "default", load the default config
if configDirectory == ReservedDefaultConfigName {
return LoadDefaultNodeConfig()
}
// if the provided config directory has both config.yml and keys.yml files, load it
if HasNodeConfigFiles(configDirectory) {
return config.LoadConfig(configDirectory, "", false)
}
// if not, check with the user's config home directory
configPath := filepath.Join(GetNodeConfigHomeDir(), configDirectory, "config.yml")
if _, err := os.Stat(configPath); os.IsNotExist(err) {
// Otherwise, the config with this name or location does not exist, return an error
// and allow the caller of this function to handle it
return nil, errors.New(ErrConfigNotFoundErrorMessage)
}
return config.LoadConfig(configDirectory, "", false)
}
// HasNodeConfigFiles checks if a directory contains both config.yml and keys.yml files
func HasNodeConfigFiles(dirPath string) bool {
configPath := filepath.Join(dirPath, "config.yml")
keysPath := filepath.Join(dirPath, "keys.yml")
// Check if both files exist
configExists := false
keysExists := false
if _, err := os.Stat(configPath); !os.IsNotExist(err) {
configExists = true
}
if _, err := os.Stat(keysPath); !os.IsNotExist(err) {
keysExists = true
}
return configExists && keysExists
}
func SetDefaultNodeConfig(configName string) error {
NodeConfigDir := GetNodeConfigHomeDir()
configDir := filepath.Join(NodeConfigDir, configName)
userLookup, err := GetCurrentSudoUser()
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting current user: %v\n", err)
os.Exit(1)
}
if err := ValidateAndCreateDir(configDir, userLookup); err != nil {
return err
}
// Construct the source directory path
sourceDir := filepath.Join(NodeConfigDir, configName)
// Check if source directory exists
if _, err := os.Stat(sourceDir); os.IsNotExist(err) {
fmt.Printf("Config directory does not exist: %s\n", sourceDir)
os.Exit(1)
}
// Check if the source directory has both config.yml and keys.yml files
if !HasNodeConfigFiles(sourceDir) {
fmt.Printf(ErrNotValidConfigDirMessage+": %s\n", sourceDir)
os.Exit(1)
}
// Construct the default directory path
defaultDir := filepath.Join(NodeConfigDir, ReservedDefaultConfigName)
// Create the symlink
if err := CreateSymlink(sourceDir, defaultDir); err != nil {
fmt.Printf("Failed to create symlink: %s\n", err)
os.Exit(1)
}
return nil
}
func CreateDefaultNodeConfig(name string) (*config.Config, error) {
userLookup, err := GetCurrentSudoUser()
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting current user: %v\n", err)
os.Exit(1)
}
// create the config directory
configsDir := GetNodeConfigHomeDir()
configPath := filepath.Join(configsDir, name)
ValidateAndCreateDir(configPath, userLookup)
// create the default config files
nodeConfig, err := config.LoadConfig(configPath, "", false)
if err != nil {
return nil, err
}
// make sure the config directory is owned by the current user
ChownPath(configPath, userLookup, true)
// now set the default config alias for use in qclient commands
SetDefaultNodeConfig(name)
return nodeConfig, nil
}
func GetAccountFromNodeConfig(config *config.Config) ([]byte, error) {
peerId := GetPeerIDFromConfig(config)
addr, err := poseidon.HashBytes([]byte(peerId))
if err != nil {
panic(err)
}
return addr.FillBytes(make([]byte, 32)), nil
}