diff --git a/abciapp/app.go b/blockchain/abci.go similarity index 99% rename from abciapp/app.go rename to blockchain/abci.go index 9001089..4ad3558 100644 --- a/abciapp/app.go +++ b/blockchain/abci.go @@ -1,4 +1,4 @@ -package abciapp +package blockchain import ( "bytes" diff --git a/blockchain/main.go b/blockchain/main.go new file mode 100644 index 0000000..3f40e38 --- /dev/null +++ b/blockchain/main.go @@ -0,0 +1,141 @@ +package blockchain + +import ( + "context" + "fmt" + + "lbc/cfg" + "os" + + "github.com/dgraph-io/badger" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/log" + nm "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/p2p" + "github.com/tendermint/tendermint/privval" + "github.com/tendermint/tendermint/proxy" + tmTypes "github.com/tendermint/tendermint/types" +) + +func openBadger(path string) (*badger.DB, error) { + return badger.Open(badger.DefaultOptions(path).WithTruncate(true)) +} + +func newTendermint(app abci.Application, config *cfg.Config, laddrReturner chan string) (*nm.Node, error) { + config.P2P.ListenAddress = "tcp://" + <-laddrReturner + + //if config.P2P.PersistentPeers == "" { + config.P2P.PersistentPeers = <-laddrReturner + //} else { + // <- laddrReturner + //} + + var pv tmTypes.PrivValidator + if _, err := os.Stat(config.PrivValidatorKeyFile()); err == nil { + pv = privval.LoadFilePV( + config.PrivValidatorKeyFile(), + config.PrivValidatorStateFile(), + ) + } else { + fmt.Println("⚠️ priv_validator_key.json not found. Node will run as non-validator.") + pv = tmTypes.NewMockPV() + } + + nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile()) + if err != nil { + return nil, fmt.Errorf("load node key: %w", err) + } + + clientCreator := proxy.NewLocalClientCreator(app) + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + + return nm.NewNode( + config, + pv, + nodeKey, + clientCreator, + nm.DefaultGenesisDocProviderFunc(config), + nm.DefaultDBProvider, + nm.DefaultMetricsProvider(config.Instrumentation), + logger, + ) +} + +func GetNodeInfo(config *cfg.Config, dbPath string) (p2p.NodeInfo, error) { + db, err := openBadger(dbPath) + if err != nil { + return nil, fmt.Errorf("failed to open badger db to get node info", err) + } + defer db.Close() + + app := NewKVStoreApplication(db) + + nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile()) + if err != nil { + return nil, fmt.Errorf("load node key: %w", err) + } + + clientCreator := proxy.NewLocalClientCreator(app) + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + var pv tmTypes.PrivValidator + if _, err := os.Stat(config.PrivValidatorKeyFile()); err == nil { + pv = privval.LoadFilePV( + config.PrivValidatorKeyFile(), + config.PrivValidatorStateFile(), + ) + } else { + fmt.Println("⚠️ priv_validator_key.json not found. Node will run as non-validator.") + pv = tmTypes.NewMockPV() + } + + config.P2P.PersistentPeers = "" + + node, err := nm.NewNode( + config, + pv, + nodeKey, + clientCreator, + nm.DefaultGenesisDocProviderFunc(config), + nm.DefaultDBProvider, + nm.DefaultMetricsProvider(config.Instrumentation), + logger, + ) + + if err != nil { + return nil, err + } + return node.NodeInfo(), nil + +} + +// В blockchain/run.go +func Run(ctx context.Context, dbPath string, config *cfg.Config, laddrReturner chan string) error { + db, err := openBadger(dbPath) + if err != nil { + return fmt.Errorf("open badger db: %w", err) + } + defer db.Close() + + app := NewKVStoreApplication(db) + node, err := newTendermint(app, config, laddrReturner) + if err != nil { + return fmt.Errorf("build node: %w", err) + } + if err := node.Start(); err != nil { + return fmt.Errorf("start node: %w", err) + } + defer func() { + + }() + + // ждём контекст или внутренних ошибок узла + select { + case <-ctx.Done(): + case <-node.Quit(): // Tendermint закрылся сам + return err + // Node quit signal received + } + node.Stop() + node.Wait() + return nil +} diff --git a/configfunctions/configfunctions.go b/cfg/configfunctions.go similarity index 70% rename from configfunctions/configfunctions.go rename to cfg/configfunctions.go index a259988..a8f734c 100644 --- a/configfunctions/configfunctions.go +++ b/cfg/configfunctions.go @@ -1,10 +1,11 @@ -package configfunctions +package cfg import ( "encoding/hex" "encoding/json" "flag" "fmt" + "io" "lbc/yggdrasil" "os" "path/filepath" @@ -18,11 +19,44 @@ import ( tmTypes "github.com/tendermint/tendermint/types" ) +type Config = cfg.Config + var ( yggListenPort = 4224 yggKeyPath = flag.String("ygg-key", "./config/yggdrasil.key", "Path to Yggdrasil key file") ) +func copyFile(src, dst string) error { + in, err := os.Open(src) + if err != nil { + return err + } + defer in.Close() + + if err = os.MkdirAll(filepath.Dir(dst), 0o700); err != nil { + return err + } + + out, err := os.Create(dst) + if err != nil { + return err + } + defer func() { + _ = out.Sync() + _ = out.Close() + }() + + _, err = io.Copy(out, in) + return err +} + +func LoadViperConfig(path string) (*viper.Viper, error) { + v := viper.New() + v.SetConfigFile(path) + err := v.ReadInConfig() + return v, err +} + func InitTendermintFiles(config *cfg.Config, isGenesis bool, chainName string) error { if err := os.MkdirAll(filepath.Dir(config.PrivValidatorKeyFile()), 0700); err != nil { return err @@ -214,3 +248,59 @@ func UpdateGenesisJson(nodeInfo p2p.NodeInfo, v *viper.Viper, defaultConfigDirec panic(err) } } + +func InitGenesis(chainName, defaultConfigPath string) (*cfg.Config, *viper.Viper) { + config := cfg.DefaultConfig() + config.RootDir = filepath.Dir(filepath.Dir(defaultConfigPath)) + + nodeinfo := p2p.DefaultNodeInfo{} + viper := WriteConfig(config, &defaultConfigPath, nodeinfo) + if err := InitTendermintFiles(config, true, chainName); err != nil { + fmt.Fprintf(os.Stderr, "Failed to init files: %v\n", err) + panic(err) + } + + return config, viper +} + +func InitJoiner(chainName, defaultConfigPath, path string) error { + config := cfg.DefaultConfig() + config.RootDir = filepath.Dir(filepath.Dir(defaultConfigPath)) + + if err := copyFile(path, config.GenesisFile()); err != nil { + fmt.Fprintln(os.Stderr, "не удалось скопировать genesis.json:", err) + os.Exit(3) + } + + nodeinfo := p2p.DefaultNodeInfo{} + WriteConfig(config, &defaultConfigPath, nodeinfo) + //viper := cfg.WriteConfig(config, &defaultConfigPath, nodeinfo) + if err := InitTendermintFiles(config, false, chainName); err != nil { + fmt.Fprintf(os.Stderr, "Failed to init files: %v\n", err) + panic(err) + } + + //node, db, err := buildNode() + //if err != nil { + // panic(err) + //} + //defer db.Close() + + //cfg.WriteConfig(config, &defaultConfigPath, node.NodeInfo()) + + //if err := os.MkdirAll(filepath.Join(config.RootDir, "data"), 0o700); err != nil { + // fmt.Fprintln(os.Stderr, "не удалось создать директорию data") + // os.Exit(1) + //} + + if _, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()); err != nil { + return fmt.Errorf("ошибка генерации node_key.json") + } + + pv := privval.GenFilePV( + config.PrivValidatorKeyFile(), + config.PrivValidatorStateFile(), + ) + pv.Save() + return nil +} diff --git a/cli/init.go b/cli/init.go index abe7eb0..c50841f 100644 --- a/cli/init.go +++ b/cli/init.go @@ -2,7 +2,10 @@ package cli import ( "fmt" + "lbc/blockchain" + "lbc/cfg" "os" + "path/filepath" "github.com/spf13/cobra" ) @@ -14,13 +17,23 @@ var initCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { switch args[0] { case "genesis": - initGenesis() + config, viper := cfg.InitGenesis(chainName, defaultConfigPath) + nodeinfo, err := blockchain.GetNodeInfo(config, dbPath) + if err != nil { + fmt.Printf("Error: %w", err) + panic(err) + } + + cfg.UpdateGenesisJson(nodeinfo, viper, filepath.Dir(defaultConfigPath)) + fmt.Println("Genesis node initialized.") case "join": if len(args) < 2 { fmt.Println("Укажите путь к genesis.json") os.Exit(1) } - initJoiner(args[1]) + cfg.InitJoiner(chainName, defaultConfigPath, args[1]) + + fmt.Println("Joiner node initialized.") default: fmt.Printf("Неизвестный режим init: %s\n", args[0]) os.Exit(1) diff --git a/cli/root.go b/cli/root.go index ccc3e75..60a278d 100644 --- a/cli/root.go +++ b/cli/root.go @@ -1,17 +1,66 @@ package cli import ( + "context" "fmt" + "lbc/blockchain" + "lbc/cfg" + "lbc/yggdrasil" "os" + "os/signal" + "syscall" "github.com/spf13/cobra" ) +var defaultConfigPath string +var dbPath string +var chainName string + +func init() { + rootCmd.PersistentFlags().StringVar(&defaultConfigPath, "config", "./config/config.toml", "Путь к конфигурационному файлу") + rootCmd.PersistentFlags().StringVar(&dbPath, "badger", "./badger", "Путь к базе данных BadgerDB") + rootCmd.PersistentFlags().StringVar(&chainName, "chainname", "lbc-chain", "Название цепочки блоков") +} + var rootCmd = &cobra.Command{ Use: "lbc", Short: "Лёгкий блокчейн координатор", Run: func(cmd *cobra.Command, args []string) { - runNode() + //Run() + v, err := cfg.LoadViperConfig(defaultConfigPath) + if err != nil { + fmt.Fprintf(os.Stderr, `Конфигурационный файл не найден: %v + + Похоже, что нода ещё не инициализирована. + + Чтобы создать необходимые файлы, запусти одну из следующих команд: + + lbc --init=genesis # если это новая цепочка + lbc --init=join # если ты присоединяешься к существующей + + По умолчанию файл конфигурации ищется по пути: %s + `, err, defaultConfigPath) + os.Exit(1) + } + + config, err := cfg.ReadConfig(defaultConfigPath) + if err != nil { + fmt.Printf("конфигурация не прочитана: %w", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + laddrReturner := make(chan string, 2) + go yggdrasil.Yggdrasil(v, laddrReturner) + go blockchain.Run(ctx, dbPath, config, laddrReturner) + + if err != nil { + // TODO exitWithError("error creating node", err) + } + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) + <-sigCh // ждём SIGINT/SIGTERM + cancel() // говорим горутинам завершаться }, } diff --git a/cli/run.go b/cli/run.go deleted file mode 100644 index eae96e1..0000000 --- a/cli/run.go +++ /dev/null @@ -1,242 +0,0 @@ -package cli - -import ( - "fmt" - "io" - - abciApp "lbc/abciapp" - cfg "lbc/configfunctions" - "lbc/yggdrasil" - "os" - "os/signal" - "path/filepath" - "syscall" - - "github.com/dgraph-io/badger" - "github.com/spf13/viper" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" - nm "github.com/tendermint/tendermint/node" - "github.com/tendermint/tendermint/p2p" - "github.com/tendermint/tendermint/privval" - "github.com/tendermint/tendermint/proxy" - tmTypes "github.com/tendermint/tendermint/types" -) - -var defaultConfigPath string -var dbPath string -var chainName string - -func init() { - rootCmd.PersistentFlags().StringVar(&defaultConfigPath, "config", "./config/config.toml", "Путь к конфигурационному файлу") - rootCmd.PersistentFlags().StringVar(&dbPath, "badger", "./badger", "Путь к базе данных BadgerDB") - rootCmd.PersistentFlags().StringVar(&chainName, "chainname", "lbc-chain", "Название цепочки блоков") -} - -func newTendermint(app abci.Application, configFile string, v *viper.Viper) (*nm.Node, error) { - config, err := cfg.ReadConfig(configFile) - if err != nil { - return nil, fmt.Errorf("конфигурация не прочитана: %w", err) - } - - laddrReturner := make(chan string, 2) - - config.P2P.PersistentPeers = cfg.ReadP2Peers(configFile) - //v.Set("p2p.persistent_peers", config.P2P.PersistentPeers) - //v.Set("") - - go yggdrasil.Yggdrasil(v, laddrReturner) - config.P2P.ListenAddress = "tcp://" + <-laddrReturner - - //if config.P2P.PersistentPeers == "" { - config.P2P.PersistentPeers = <-laddrReturner - //} else { - // <- laddrReturner - //} - - var pv tmTypes.PrivValidator - if _, err := os.Stat(config.PrivValidatorKeyFile()); err == nil { - pv = privval.LoadFilePV( - config.PrivValidatorKeyFile(), - config.PrivValidatorStateFile(), - ) - } else { - fmt.Println("⚠️ priv_validator_key.json not found. Node will run as non-validator.") - pv = tmTypes.NewMockPV() - } - - nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile()) - if err != nil { - return nil, fmt.Errorf("load node key: %w", err) - } - - clientCreator := proxy.NewLocalClientCreator(app) - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - - return nm.NewNode( - config, - pv, - nodeKey, - clientCreator, - nm.DefaultGenesisDocProviderFunc(config), - nm.DefaultDBProvider, - nm.DefaultMetricsProvider(config.Instrumentation), - logger, - ) -} - -func exitWithError(msg string, err error) { - fmt.Fprintf(os.Stderr, "%s: %v\n", msg, err) - os.Exit(1) -} - -func loadViperConfig(path string) (*viper.Viper, error) { - v := viper.New() - v.SetConfigFile(path) - err := v.ReadInConfig() - return v, err -} - -func openBadger(path string) (*badger.DB, error) { - return badger.Open(badger.DefaultOptions(path).WithTruncate(true)) -} - -func buildNode() (*nm.Node, *badger.DB, error) { - v, err := loadViperConfig(defaultConfigPath) - if err != nil { - fmt.Fprintf(os.Stderr, `Конфигурационный файл не найден: %v - -Похоже, что нода ещё не инициализирована. - -Чтобы создать необходимые файлы, запусти одну из следующих команд: - - lbc --init=genesis # если это новая цепочка - lbc --init=join # если ты присоединяешься к существующей - -По умолчанию файл конфигурации ищется по пути: %s -`, err, defaultConfigPath) - os.Exit(1) - } - - db, err := openBadger(dbPath) - if err != nil { - exitWithError("failed to open badger db", err) - } - - app := abciApp.NewKVStoreApplication(db) - - node, err := newTendermint(app, defaultConfigPath, v) - if err != nil { - exitWithError("error creating node", err) - } - return node, db, err -} - -func copyFile(src, dst string) error { - in, err := os.Open(src) - if err != nil { - return err - } - defer in.Close() - - if err = os.MkdirAll(filepath.Dir(dst), 0o700); err != nil { - return err - } - - out, err := os.Create(dst) - if err != nil { - return err - } - defer func() { - _ = out.Sync() - _ = out.Close() - }() - - _, err = io.Copy(out, in) - return err -} - -func runNode() { - node, db, err := buildNode() - if err != nil { - exitWithError("failed to build node", err) - } - defer db.Close() - - if err := node.Start(); err != nil { - exitWithError("failed to start node", err) - } - defer func() { - node.Stop() - node.Wait() - }() - - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - <-sigCh -} - -func initGenesis() { - config := cfg.DefaultConfig() - config.RootDir = filepath.Dir(filepath.Dir(defaultConfigPath)) - - nodeinfo := p2p.DefaultNodeInfo{} - viper := cfg.WriteConfig(config, &defaultConfigPath, nodeinfo) - if err := cfg.InitTendermintFiles(config, true, chainName); err != nil { - fmt.Fprintf(os.Stderr, "Failed to init files: %v\n", err) - panic(err) - } - - node, db, err := buildNode() - if err != nil { - panic(err) - } - db.Close() - - cfg.UpdateGenesisJson(node.NodeInfo(), viper, filepath.Dir(defaultConfigPath)) - fmt.Println("Genesis node initialized.") -} - -func initJoiner(path string) { - config := cfg.DefaultConfig() - config.RootDir = filepath.Dir(filepath.Dir(defaultConfigPath)) - - if err := copyFile(path, config.GenesisFile()); err != nil { - fmt.Fprintln(os.Stderr, "не удалось скопировать genesis.json:", err) - os.Exit(3) - } - - nodeinfo := p2p.DefaultNodeInfo{} - cfg.WriteConfig(config, &defaultConfigPath, nodeinfo) - //viper := cfg.WriteConfig(config, &defaultConfigPath, nodeinfo) - if err := cfg.InitTendermintFiles(config, false, chainName); err != nil { - fmt.Fprintf(os.Stderr, "Failed to init files: %v\n", err) - panic(err) - } - - node, db, err := buildNode() - if err != nil { - panic(err) - } - defer db.Close() - - cfg.WriteConfig(config, &defaultConfigPath, node.NodeInfo()) - - //if err := os.MkdirAll(filepath.Join(config.RootDir, "data"), 0o700); err != nil { - // fmt.Fprintln(os.Stderr, "не удалось создать директорию data") - // os.Exit(1) - //} - - if _, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()); err != nil { - fmt.Fprintln(os.Stderr, "ошибка генерации node_key.json") - os.Exit(2) - } - - pv := privval.GenFilePV( - config.PrivValidatorKeyFile(), - config.PrivValidatorStateFile(), - ) - pv.Save() - - fmt.Println("Joiner node initialized.") -} diff --git a/genesis.json b/genesis.json deleted file mode 100644 index bca55dd..0000000 --- a/genesis.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "app_hash": "", - "chain_id": "lbc-chain", - "consensus_params": { - "block": { - "max_bytes": "22020096", - "max_gas": "-1", - "time_iota_ms": "1000" - }, - "evidence": { - "max_age_duration": "172800000000000", - "max_age_num_blocks": "100000", - "max_bytes": "1048576" - }, - "validator": { - "pub_key_types": [ - "ed25519" - ] - }, - "version": {} - }, - "genesis_time": "2025-07-12T17:34:34.7567451Z", - "initial_height": "0", - "p2peers": "f8366fe22e5a3cd64281ecfc6e50075903848ab9@ygg://[200:6687:b756:51a2:1147:aef0:9011:c142]:4224", - "validators": [ - { - "address": "F1585752261F319FE0A9E2097825A2807622AE5A", - "name": "DESKTOP-HN9RCT8", - "power": "10", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "gnPCTB+kqaiw2TmFwrZYoCcWiPO3SdTf1IB7rEdBulE=" - } - } - ] -} \ No newline at end of file diff --git a/autopeering/autopeering.go b/yggdrasil/autopeering.go similarity index 98% rename from autopeering/autopeering.go rename to yggdrasil/autopeering.go index 947cbfa..b5b5241 100644 --- a/autopeering/autopeering.go +++ b/yggdrasil/autopeering.go @@ -1,4 +1,4 @@ -package autopeering +package yggdrasil import ( "context" @@ -50,7 +50,7 @@ func readPeersFile(path string) []url.URL { // connection strings. If fetching fails, it falls back to reading peers from // peers.txt in the current working directory. It returns an empty slice if no // peers can be retrieved. -func GetPublicPeers() []url.URL { +func getPublicPeers() []url.URL { tempDir, err := os.MkdirTemp("", "public-peers-*") if err != nil { return readPeersFile("peers.txt") diff --git a/yggdrasil/keys.go b/yggdrasil/keys.go new file mode 100644 index 0000000..c507d70 --- /dev/null +++ b/yggdrasil/keys.go @@ -0,0 +1,97 @@ +package yggdrasil + +import ( + "crypto/ed25519" + "encoding/hex" + "fmt" + "os" + "strings" + + "github.com/gologme/log" + "github.com/spf13/viper" + + yggConfig "github.com/yggdrasil-network/yggdrasil-go/src/config" + "github.com/yggdrasil-network/yggdrasil-go/src/core" +) + +func GeneratePrivateKey() yggConfig.KeyBytes { + return yggConfig.GenerateConfig().PrivateKey +} + +func GetPublicKey(keyPath string) (ed25519.PublicKey, error) { + data, err := os.ReadFile(keyPath) + if err != nil { + return ed25519.PublicKey{}, err + } + + decoded, err := hex.DecodeString(strings.TrimSpace(string(data))) + if err != nil { + return ed25519.PublicKey{}, err + } + + if len(decoded) != ed25519.PrivateKeySize { + return ed25519.PublicKey{}, fmt.Errorf("invalid private key size: %d", len(decoded)) + } + + privateKey := ed25519.PrivateKey(decoded) + return privateKey.Public().(ed25519.PublicKey), nil +} + +func GetYggdrasilAddress(config *viper.Viper) string { + //var remoteTcp types.TCPRemoteMappings + ygg := config.Sub("yggdrasil") + if ygg == nil { + return "" + } + + //laddr := config.Sub("p2p").GetString("laddr") + //remoteTcp.Set(laddr) + + cfg := yggConfig.GenerateConfig() + + cfg.AdminListen = ygg.GetString("admin_listen") + cfg.Listen = ygg.GetStringSlice("listen") + cfg.Peers = ygg.GetStringSlice("peers") + cfg.AllowedPublicKeys = ygg.GetStringSlice("allowed-public-keys") + cfg.PrivateKeyPath = ygg.GetString("private-key-file") + + logger := log.Default() + + n := &node{} + + // Setup the Yggdrasil node itself. + { + options := []core.SetupOption{ + core.NodeInfo(cfg.NodeInfo), + core.NodeInfoPrivacy(cfg.NodeInfoPrivacy), + } + for _, addr := range cfg.Listen { + options = append(options, core.ListenAddress(addr)) + } + for _, peer := range cfg.Peers { + options = append(options, core.Peer{URI: peer}) + } + for intf, peers := range cfg.InterfacePeers { + for _, peer := range peers { + options = append(options, core.Peer{URI: peer, SourceInterface: intf}) + } + } + for _, allowed := range cfg.AllowedPublicKeys { + k, err := hex.DecodeString(allowed) + if err != nil { + panic(err) + } + options = append(options, core.AllowedPublicKey(k[:])) + } + + var err error + if n.core, err = core.New(cfg.Certificate, logger, options...); err != nil { + panic(err) + } + + address := n.core.Address() + n.core.Stop() + return address.String() + } + +} diff --git a/yggdrasil/yggdrasil.go b/yggdrasil/main.go similarity index 72% rename from yggdrasil/yggdrasil.go rename to yggdrasil/main.go index ad6efe0..3836c4f 100644 --- a/yggdrasil/yggdrasil.go +++ b/yggdrasil/main.go @@ -2,17 +2,12 @@ package yggdrasil import ( "context" - "crypto/ed25519" "encoding/hex" - "errors" "fmt" - "lbc/autopeering" - ppp "lbc/persistentpeersparser" "net" "os" "os/signal" "regexp" - "runtime" "strings" "syscall" @@ -45,88 +40,6 @@ type TCPRemoteListenerMapping struct { Mapped *net.TCPListener } -func GeneratePrivateKey() yggConfig.KeyBytes { - return yggConfig.GenerateConfig().PrivateKey -} - -func GetPublicKey(keyPath string) (ed25519.PublicKey, error) { - data, err := os.ReadFile(keyPath) - if err != nil { - return ed25519.PublicKey{}, err - } - - decoded, err := hex.DecodeString(strings.TrimSpace(string(data))) - if err != nil { - return ed25519.PublicKey{}, err - } - - if len(decoded) != ed25519.PrivateKeySize { - return ed25519.PublicKey{}, fmt.Errorf("invalid private key size: %d", len(decoded)) - } - - privateKey := ed25519.PrivateKey(decoded) - return privateKey.Public().(ed25519.PublicKey), nil -} - -func GetYggdrasilAddress(config *viper.Viper) string { - //var remoteTcp types.TCPRemoteMappings - ygg := config.Sub("yggdrasil") - if ygg == nil { - return "" - } - - //laddr := config.Sub("p2p").GetString("laddr") - //remoteTcp.Set(laddr) - - cfg := yggConfig.GenerateConfig() - - cfg.AdminListen = ygg.GetString("admin_listen") - cfg.Listen = ygg.GetStringSlice("listen") - cfg.Peers = ygg.GetStringSlice("peers") - cfg.AllowedPublicKeys = ygg.GetStringSlice("allowed-public-keys") - cfg.PrivateKeyPath = ygg.GetString("private-key-file") - - logger := log.Default() - - n := &node{} - - // Setup the Yggdrasil node itself. - { - options := []core.SetupOption{ - core.NodeInfo(cfg.NodeInfo), - core.NodeInfoPrivacy(cfg.NodeInfoPrivacy), - } - for _, addr := range cfg.Listen { - options = append(options, core.ListenAddress(addr)) - } - for _, peer := range cfg.Peers { - options = append(options, core.Peer{URI: peer}) - } - for intf, peers := range cfg.InterfacePeers { - for _, peer := range peers { - options = append(options, core.Peer{URI: peer, SourceInterface: intf}) - } - } - for _, allowed := range cfg.AllowedPublicKeys { - k, err := hex.DecodeString(allowed) - if err != nil { - panic(err) - } - options = append(options, core.AllowedPublicKey(k[:])) - } - - var err error - if n.core, err = core.New(cfg.Certificate, logger, options...); err != nil { - panic(err) - } - - address := n.core.Address() - n.core.Stop() - return address.String() - } - -} - // The main function is responsible for configuring and starting Yggdrasil. func Yggdrasil(config *viper.Viper, ch chan string) { var remoteTcp types.TCPRemoteMappings @@ -157,9 +70,9 @@ func Yggdrasil(config *viper.Viper, ch chan string) { ch <- remoteTcp[0].Mapped.String() peers := p2p.GetString("persistent_peers") - parsed, err := ppp.ParseEntries(peers) + parsed, err := ParseEntries(peers) if err != nil { - parsed = []ppp.ParsedEntry{} + parsed = []ParsedEntry{} ch <- "" log.Warnln("Warning: persistent peers has an error") } @@ -169,7 +82,7 @@ func Yggdrasil(config *viper.Viper, ch chan string) { cfg.AdminListen = ygg.GetString("admin_listen") cfg.Listen = ygg.GetStringSlice("listen") if ygg.GetString("peers") == "auto" { - publicPeers := autopeering.GetPublicPeers() + publicPeers := getPublicPeers() var urlsAsStrings []string for _, u := range publicPeers { urlsAsStrings = append(urlsAsStrings, u.String()) @@ -372,23 +285,4 @@ func Yggdrasil(config *viper.Viper, ch chan string) { n.core.Stop() } -// Helper to detect if socket address is in use -// https://stackoverflow.com/a/52152912 -func isErrorAddressAlreadyInUse(err error) bool { - var eOsSyscall *os.SyscallError - if !errors.As(err, &eOsSyscall) { - return false - } - var errErrno syscall.Errno // doesn't need a "*" (ptr) because it's already a ptr (uintptr) - if !errors.As(eOsSyscall, &errErrno) { - return false - } - if errors.Is(errErrno, syscall.EADDRINUSE) { - return true - } - const WSAEADDRINUSE = 10048 - if runtime.GOOS == "windows" && errErrno == WSAEADDRINUSE { - return true - } - return false -} + diff --git a/autopeering/peers.txt b/yggdrasil/peers.txt similarity index 100% rename from autopeering/peers.txt rename to yggdrasil/peers.txt diff --git a/persistentpeersparser/persistentpeersparser.go b/yggdrasil/persistentpeersparser.go similarity index 97% rename from persistentpeersparser/persistentpeersparser.go rename to yggdrasil/persistentpeersparser.go index e6033a1..892956e 100644 --- a/persistentpeersparser/persistentpeersparser.go +++ b/yggdrasil/persistentpeersparser.go @@ -1,4 +1,4 @@ -package persistentpeersparser +package yggdrasil import ( "fmt"