major release

This commit is contained in:
Gregory Bednov 2025-07-12 12:07:50 +03:00
commit 9947861ff8
13 changed files with 372 additions and 254 deletions

View file

@ -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 ./...

9
.gitignore vendored
View file

@ -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

View file

@ -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)

View file

@ -1,4 +1,4 @@
package main
package abciapp
import (
"bytes"

View file

@ -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

33
cli/init.go Normal file
View file

@ -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)
}

23
cli/root.go Normal file
View file

@ -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)
}
}

223
cli/run.go Normal file
View file

@ -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.")
}

View file

@ -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)
}
}

22
go.mod
View file

@ -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

9
go.sum
View file

@ -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=

160
main.go
View file

@ -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()
}

View file

@ -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)
{