// Copyright (c) 2017-2026 Lethean (https://lt.hn) // // Licensed under the European Union Public Licence (EUPL) version 1.2. // SPDX-License-Identifier: EUPL-1.2 package blockchain import ( "fmt" "net" "os" "path/filepath" coreio "dappco.re/go/core/io" coreerr "dappco.re/go/core/log" "dappco.re/go/core/blockchain/config" "github.com/spf13/cobra" ) const defaultChainSeed = "seeds.lthn.io:36942" // AddChainCommands registers the `chain` command group on a Cobra root. // // Example: // // cli.WithCommands("chain", blockchain.AddChainCommands) // // The command group owns the explorer and sync subcommands, so the // command path documents the node features directly. func AddChainCommands(root *cobra.Command) { var ( dataDir string seed string testnet bool ) chainCmd := &cobra.Command{ Use: "chain", Short: "Lethean blockchain node", Long: "Manage the Lethean blockchain — sync, explore, and mine.", } chainCmd.PersistentFlags().StringVar(&dataDir, "data-dir", defaultChainDataDirPath(), "blockchain data directory") chainCmd.PersistentFlags().StringVar(&seed, "seed", defaultChainSeed, "seed peer address (host:port)") chainCmd.PersistentFlags().BoolVar(&testnet, "testnet", false, "use testnet") chainCmd.AddCommand( newChainExplorerCommand(&dataDir, &seed, &testnet), newChainSyncCommand(&dataDir, &seed, &testnet), ) root.AddCommand(chainCmd) } func chainConfigForSeed(testnet bool, seed string) (config.ChainConfig, []config.HardFork, string) { if testnet { if seed == defaultChainSeed { seed = "localhost:46942" } return config.Testnet, config.TestnetForks, seed } return config.Mainnet, config.MainnetForks, seed } func defaultChainDataDirPath() string { home, err := os.UserHomeDir() if err != nil { return ".lethean" } return filepath.Join(home, ".lethean", "chain") } func ensureChainDataDirExists(dataDir string) error { if err := coreio.Local.EnsureDir(dataDir); err != nil { return coreerr.E("ensureChainDataDirExists", "create data dir", err) } return nil } func validateChainOptions(dataDir, seed string) error { if dataDir == "" { return coreerr.E("validateChainOptions", "data dir is required", nil) } if seed == "" { return coreerr.E("validateChainOptions", "seed is required", nil) } if _, _, err := net.SplitHostPort(seed); err != nil { return coreerr.E("validateChainOptions", fmt.Sprintf("seed %q must be host:port", seed), err) } return nil }