diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 09a5b81..06c0e70 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -14,15 +14,15 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.24' + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.24' - - name: Build - run: go build -v ./... + - name: Build + run: go build -v ./... - - name: Test - run: go test -v ./... + - name: Test + run: go test -v ./... diff --git a/.gitignore b/.gitignore index 7c3640b..fb9f106 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,15 @@ config/ data/ yggstack/ .vscode/ + +# Test binary, built with `go test -c` *.test + +# Output of the go coverage tool, specifically when used with LiteIDE *.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file go.work diff --git a/README.md b/README.md index 67d7c7d..f11d9a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # lbc +<<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> d8e9608 (Fix key parsing and update docs) Experimental blockchain implementation built on Tendermint and BadgerDB. @@ -27,3 +31,9 @@ go run . ``` See `--help` for a full list of available options. +<<<<<<< HEAD +======= +blockchain for social cooperation +>>>>>>> 1e4be97 (Initial commit) +======= +>>>>>>> d8e9608 (Fix key parsing and update docs) diff --git a/app.go b/abciapp/app.go similarity index 99% rename from app.go rename to abciapp/app.go index c793771..9001089 100644 --- a/app.go +++ b/abciapp/app.go @@ -1,4 +1,4 @@ -package main +package abciapp import ( "bytes" diff --git a/autopeering/peers.txt b/autopeering/peers.txt index b529e2c..f20c43c 100644 --- a/autopeering/peers.txt +++ b/autopeering/peers.txt @@ -106,7 +106,6 @@ tcp://longseason.1200bps.xyz:13121 tcp://149.28.123.138:8008 tcp://lancis.iscute.moe:49273 tcp://zabugor.itrus.su:7991 -tcp://supergay.network:9002 tls://108.175.10.127:61216 tls://longseason.1200bps.xyz:13122 tls://167.160.89.98:7040 diff --git a/cli/init.go b/cli/init.go new file mode 100644 index 0000000..abe7eb0 --- /dev/null +++ b/cli/init.go @@ -0,0 +1,33 @@ +package cli + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var initCmd = &cobra.Command{ + Use: "init [genesis|join] [genesis-path]", + Short: "Инициализация ноды: genesis или join", + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + switch args[0] { + case "genesis": + initGenesis() + case "join": + if len(args) < 2 { + fmt.Println("Укажите путь к genesis.json") + os.Exit(1) + } + initJoiner(args[1]) + default: + fmt.Printf("Неизвестный режим init: %s\n", args[0]) + os.Exit(1) + } + }, +} + +func init() { + rootCmd.AddCommand(initCmd) +} diff --git a/cli/root.go b/cli/root.go new file mode 100644 index 0000000..ccc3e75 --- /dev/null +++ b/cli/root.go @@ -0,0 +1,23 @@ +package cli + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var rootCmd = &cobra.Command{ + Use: "lbc", + Short: "Лёгкий блокчейн координатор", + Run: func(cmd *cobra.Command, args []string) { + runNode() + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "ошибка: %v\n", err) + os.Exit(1) + } +} diff --git a/cli/run.go b/cli/run.go new file mode 100644 index 0000000..7f740a2 --- /dev/null +++ b/cli/run.go @@ -0,0 +1,223 @@ +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 + +func init() { + rootCmd.PersistentFlags().StringVar(&defaultConfigPath, "config", "./config/config.toml", "Путь к конфигурационному файлу") + rootCmd.PersistentFlags().StringVar(&dbPath, "badger", "./badger", "Путь к базе данных BadgerDB") +} + +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) + go yggdrasil.Yggdrasil(v, laddrReturner) + + config.P2P.ListenAddress = "tcp://" + <-laddrReturner + config.P2P.PersistentPeers = <-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 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); 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) + fmt.Println("Genesis node initialized.") +} + +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 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) + } + + 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/configfunctions/configfunctions.go b/configfunctions/configfunctions.go index 411f2e8..e51a791 100644 --- a/configfunctions/configfunctions.go +++ b/configfunctions/configfunctions.go @@ -2,6 +2,7 @@ package configfunctions import ( "encoding/hex" + "encoding/json" "flag" "fmt" "lbc/yggdrasil" @@ -75,7 +76,7 @@ func writeYggdrasilKey(path string) { os.WriteFile(path, []byte(hexKey), 0600) } -func WriteConfig(config *cfg.Config, configPath *string, isJoinerGenerator bool, nodeInfo p2p.NodeInfo) { +func WriteConfig(config *cfg.Config, configPath *string, nodeInfo p2p.NodeInfo) *viper.Viper { writeYggdrasilKey(*yggKeyPath) pubkey, err := yggdrasil.GetPublicKey(*yggKeyPath) if err != nil { @@ -115,19 +116,10 @@ func WriteConfig(config *cfg.Config, configPath *string, isJoinerGenerator bool, "private_key_file": *yggKeyPath, }) - if isJoinerGenerator { - // TODO idea what if mix persistent peers from the current persistent peers list appending current and mix them all? - nodeId := nodeInfo.ID() - myPeer := yggdrasil.GetYggdrasilAddress(v) - config.P2P.PersistentPeers = string(nodeId) + "@ygg://[" + myPeer + "]:" + strconv.Itoa(yggListenPort) - } else { - config.P2P.PersistentPeers = "" - } - v.Set("p2p", map[string]interface{}{ "use_legacy": false, "queue_type": "priority", - "laddr": strconv.Itoa(yggListenPort) + ":127.0.0.1:80", + "laddr": strconv.Itoa(yggListenPort) + ":127.0.0.1:8000", "external_address": "", // will be set automatically by Tendermint if needed "upnp": false, "bootstrap_peers": "", @@ -136,13 +128,17 @@ func WriteConfig(config *cfg.Config, configPath *string, isJoinerGenerator bool, "addr_book_strict": true, }) + nodeId := nodeInfo.ID() + myPeer := yggdrasil.GetYggdrasilAddress(v, nil) + config.P2P.PersistentPeers = string(nodeId) + "@ygg://[" + myPeer + "]:" + strconv.Itoa(yggListenPort) + err = v.WriteConfigAs(*configPath) if err != nil { fmt.Fprintf(os.Stderr, "error writing config: %v\n", err) os.Exit(1) } - fmt.Printf("Custom config written to %s\n", *configPath) + return v } func ReadConfig(configFile string) (*cfg.Config, error) { @@ -169,3 +165,28 @@ func ReadConfig(configFile string) (*cfg.Config, error) { func DefaultConfig() *cfg.Config { return cfg.DefaultConfig() } + +func UpdateGenesisJson(nodeInfo p2p.NodeInfo, v *viper.Viper) { + file, err := os.ReadFile("./config/genesis.json") // TODO remove hardocded paths + if err != nil { + panic(err) + } + + var dat map[string]any + if err := json.Unmarshal(file, &dat); err != nil { + panic(err) + } + + myPeer := yggdrasil.GetYggdrasilAddress(v, nil) + + p2peers := fmt.Sprintf("%s@ygg://[%s]:%d", nodeInfo.ID(), myPeer, yggListenPort) + dat["p2peers"] = p2peers + + out, err := json.MarshalIndent(dat, "", " ") + if err != nil { + panic(err) + } + if err := os.WriteFile("./config/genesis.json", out, 0o644); err != nil { + panic(err) + } +} diff --git a/go.mod b/go.mod index c23c815..ed5706e 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,17 @@ module lbc -go 1.24 +go 1.24.3 require ( github.com/dgraph-io/badger v1.6.2 + github.com/go-git/go-git/v5 v5.16.2 + github.com/gologme/log v1.3.0 + github.com/spf13/cobra v1.6.0 + github.com/spf13/viper v1.13.0 github.com/tendermint/tendermint v0.34.24 + github.com/things-go/go-socks5 v0.0.5 + github.com/yggdrasil-network/yggdrasil-go v0.5.12 + github.com/yggdrasil-network/yggstack v0.0.0-20250208132654-8ad1962f6456 ) require ( @@ -52,6 +59,7 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hjson/hjson-go/v4 v4.4.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -81,7 +89,6 @@ require ( github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect @@ -106,16 +113,5 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect -) - -require ( - github.com/go-git/go-git/v5 v5.16.2 - github.com/gologme/log v1.3.0 - github.com/spf13/viper v1.13.0 - github.com/things-go/go-socks5 v0.0.5 - github.com/yggdrasil-network/yggdrasil-go v0.5.12 - github.com/yggdrasil-network/yggstack v0.0.0-20250208132654-8ad1962f6456 gvisor.dev/gvisor v0.0.0-20240810013311-326fe0f2a77f // indirect ) - -replace github.com/yggdrasil-network/yggstack/cmd/yggstack => ./yggstack diff --git a/go.sum b/go.sum index d4ef62a..33265ba 100644 --- a/go.sum +++ b/go.sum @@ -117,6 +117,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= @@ -278,6 +279,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= @@ -369,6 +372,7 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= @@ -388,6 +392,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -398,9 +404,8 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= diff --git a/main.go b/main.go index 8281dbb..3b663fb 100644 --- a/main.go +++ b/main.go @@ -1,163 +1,9 @@ package main import ( - "flag" - "fmt" - - 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" + "lbc/cli" ) -var ( - defaultConfigPath = flag.String("config", "./config/config.toml", "Path to config file") - dbPath = flag.String("badger", "./badger", "Path to database") - initMode = flag.Bool("init", false, "Generate new config, keys and genesis") - initType = flag.String("mode", "genesis", "Init mode: genesis or join") - writeConfigStubPath = flag.String("joiner-config", "", "Stub for join file") -) - -func initFiles() { - config := cfg.DefaultConfig() - config.RootDir = filepath.Dir(filepath.Dir(*defaultConfigPath)) - - switch *initType { - case "genesis": - cfg.WriteConfig(config, defaultConfigPath, false, p2p.DefaultNodeInfo{}) - if err := cfg.InitTendermintFiles(config); err != nil { - fmt.Fprintf(os.Stderr, "Failed to init files: %v\n", err) - panic(err) - } - fmt.Println("Genesis node initialized.") - case "join": - cfg.WriteConfig(config, defaultConfigPath, false, p2p.DefaultNodeInfo{}) - - if err := os.MkdirAll(filepath.Join(config.RootDir, "data"), 0700); err != nil { - fmt.Fprint(os.Stderr, "не удалось создать директорию data") - os.Exit(1) - } - - if _, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()); err != nil { - fmt.Fprint(os.Stderr, "ошибка генерации node_key.json") - os.Exit(2) - } - - pv := privval.GenFilePV( - config.PrivValidatorKeyFile(), - config.PrivValidatorStateFile(), - ) - pv.Save() - - fmt.Println("Peer node initialized. Please ensure genesis.json is placed correctly.") - default: - fmt.Fprintf(os.Stderr, "Unknown mode: %s\n", *initType) - return - } -} - func main() { - flag.Parse() - - if *initMode { - initFiles() - return - } - - viper.SetConfigFile(*defaultConfigPath) - if err := viper.ReadInConfig(); err != nil { - fmt.Fprintf(os.Stderr, `Конфигурационный файл не найден: %v - - Похоже, что нода ещё не инициализирована. - - Чтобы создать необходимые файлы, запусти одну из следующих команд: - - lbc --init --mode=genesis # если это новая цепочка - lbc --init --mode=join # если ты присоединяешься к существующей - - По умолчанию файл конфигурации ищется по пути: %s - `, err, *defaultConfigPath) - os.Exit(1) - } - - db, err := badger.Open(badger.DefaultOptions(*dbPath).WithTruncate(true)) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to open badger db: %v\n", err) - os.Exit(1) - } - defer db.Close() - - app := NewKVStoreApplication(db) - - ch := make(chan string, 2) - - go yggdrasil.Yggdrasil(viper.GetViper(), ch) - - node, err := newTendermint(app, *defaultConfigPath, ch) - if err != nil { - fmt.Fprintf(os.Stderr, "error creating node: %v\n", err) - os.Exit(2) - } - - if *writeConfigStubPath != "" { - cfg.WriteConfig(node.Config(), writeConfigStubPath, true, node.NodeInfo()) - return - } - - node.Start() - defer func() { node.Stop(); node.Wait() }() - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - <-sigCh -} - -func newTendermint(app abci.Application, configFile string, laddrReturner chan string) (*nm.Node, error) { - config, err := cfg.ReadConfig(configFile) - if err != nil { - return nil, fmt.Errorf("конфигурация не прочитана") - } - config.P2P.ListenAddress = "tcp://" + <-laddrReturner - config.P2P.PersistentPeers = <-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, - ) -} + cli.Execute() +} \ No newline at end of file diff --git a/yggdrasil/yggdrasil.go b/yggdrasil/yggdrasil.go index 72799ff..dca07a0 100644 --- a/yggdrasil/yggdrasil.go +++ b/yggdrasil/yggdrasil.go @@ -6,7 +6,7 @@ import ( "encoding/hex" "errors" "fmt" - autoPeering "lbc/autopeering" + "lbc/autoPeering" ppp "lbc/persistentpeersparser" "net" "os" @@ -18,7 +18,6 @@ import ( "github.com/gologme/log" "github.com/spf13/viper" - "github.com/things-go/go-socks5" "github.com/yggdrasil-network/yggdrasil-go/src/admin" yggConfig "github.com/yggdrasil-network/yggdrasil-go/src/config" @@ -69,12 +68,20 @@ func GetPublicKey(keyPath string) (ed25519.PublicKey, error) { return privateKey.Public().(ed25519.PublicKey), nil } -func GetYggdrasilAddress(config *viper.Viper) string { +func GetYggdrasilAddress(config *viper.Viper, ch chan string) string { + var remoteTcp types.TCPRemoteMappings ygg := config.Sub("yggdrasil") if ygg == nil { return "" } + laddr := config.Sub("p2p").GetString("laddr") + remoteTcp.Set(laddr) + if ch != nil { + ch <- remoteTcp[0].Mapped.String() + ch <- "" + } + cfg := yggConfig.GenerateConfig() cfg.AdminListen = ygg.GetString("admin_listen") @@ -175,6 +182,8 @@ func Yggdrasil(config *viper.Viper, ch chan string) { cfg.Peers = ygg.GetStringSlice("peers") } + logger.Infof("Yggdrasil peers: %s", cfg.Peers) + cfg.AllowedPublicKeys = ygg.GetStringSlice("allowed-public-keys") cfg.PrivateKeyPath = ygg.GetString("private-key-file") @@ -265,62 +274,6 @@ func Yggdrasil(config *viper.Viper, ch chan string) { panic(err) } - // Create SOCKS server - { - if socks != "" { - socksOptions := []socks5.Option{ - socks5.WithDial(s.DialContext), - } - if logger.GetLevel("debug") { - socksOptions = append(socksOptions, socks5.WithLogger(logger)) - } - server := socks5.NewServer(socksOptions...) - if strings.Contains(socks, ":") { - logger.Infof("Starting SOCKS server on %s", socks) - n.socks5Tcp, err = net.Listen("tcp", socks) - if err != nil { - panic(err) - } - go func() { - err := server.Serve(n.socks5Tcp) - if err != nil { - panic(err) - } - }() - } else { - logger.Infof("Starting SOCKS server with socket file %s", socks) - n.socks5Unix, err = net.Listen("unix", socks) - if err != nil { - // If address in use, try connecting to - // the socket to see if other yggstack - // instance is listening on it - - if isErrorAddressAlreadyInUse(err) { - _, err = net.Dial("unix", socks) - if err != nil { - // Unlink dead socket if not connected - err = os.RemoveAll(socks) - if err != nil { - panic(err) - } - } else { - log.Errorf("Another yggstack instance is listening on socket '%s'", socks) - panic(err) - } - } else { - panic(err) - } - } - go func() { - err := server.Serve(n.socks5Unix) - if err != nil { - panic(err) - } - }() - } - } - } - // Create local TCP mappings (forwarding connections from local port // to remote Yggdrasil node) {