diff --git a/blockchain/abci.go b/blockchain/abci.go
index e90f342..4ad3558 100644
--- a/blockchain/abci.go
+++ b/blockchain/abci.go
@@ -1,260 +1,67 @@
package blockchain
import (
- "crypto/ed25519"
- "encoding/base64"
- "encoding/json"
- "errors"
+ "bytes"
"fmt"
- "strings"
-
- types "github.com/gregorybednov/lbc_sdk"
"github.com/dgraph-io/badger"
abci "github.com/tendermint/tendermint/abci/types"
)
-type PromiseApp struct {
+type KVStoreApplication struct {
db *badger.DB
currentBatch *badger.Txn
}
-type compoundTxRaw struct {
- Body json.RawMessage `json:"body"`
- Signature string `json:"signature"`
+func NewKVStoreApplication(db *badger.DB) *KVStoreApplication {
+ return &KVStoreApplication{db: db}
}
-type compoundBody struct {
- Promise *types.PromiseTxBody `json:"promise"`
- Commitment *types.CommitmentTxBody `json:"commitment"`
-}
-
-func NewPromiseApp(db *badger.DB) *PromiseApp {
- return &PromiseApp{db: db}
-}
-
-func hasPrefix(id, pref string) bool { return strings.HasPrefix(id, pref+":") }
-
-func requireIDPrefix(id, pref string) error {
- if strings.TrimSpace(id) == "" {
- return fmt.Errorf("missing %s id", pref)
+// Проверка транзакции (CheckTx)
+func (app *KVStoreApplication) isValid(tx []byte) uint32 {
+ parts := bytes.Split(tx, []byte("="))
+ if len(parts) != 2 {
+ return 1 // неверный формат
}
- if !hasPrefix(id, pref) {
- return fmt.Errorf("invalid %s id prefix", pref)
- }
- return nil
-}
+ key, value := parts[0], parts[1]
-func verifyAndExtractBody(db *badger.DB, tx []byte) (map[string]interface{}, error) {
- var outer struct {
- Body types.CommiterTxBody `json:"body"`
- Signature string `json:"signature"`
- }
-
- if err := json.Unmarshal(tx, &outer); err != nil {
- return nil, errors.New("invalid JSON wrapper")
- }
-
- msg, err := json.Marshal(outer.Body)
- if err != nil {
- return nil, err
- }
-
- sig, err := base64.StdEncoding.DecodeString(outer.Signature)
- if err != nil {
- return nil, errors.New("invalid signature base64")
- }
- if len(sig) != ed25519.SignatureSize {
- return nil, fmt.Errorf("invalid signature length: got %d, want %d", len(sig), ed25519.SignatureSize)
- }
-
- pubkeyB64 := strings.TrimSpace(outer.Body.CommiterPubKey)
- if pubkeyB64 == "" {
- return nil, errors.New("missing commiter pubkey")
- }
- pubkey, err := base64.StdEncoding.DecodeString(pubkeyB64)
- if err != nil {
- return nil, errors.New("invalid pubkey base64")
- }
- if len(pubkey) != ed25519.PublicKeySize {
- return nil, fmt.Errorf("invalid pubkey length: got %d, want %d", len(pubkey), ed25519.PublicKeySize)
- }
-
- if !ed25519.Verify(pubkey, msg, sig) {
- return nil, errors.New("signature verification failed")
- }
-
- var result map[string]interface{}
- if err := json.Unmarshal(msg, &result); err != nil {
- return nil, err
- }
-
- return result, nil
-}
-
-func (app *PromiseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
- compound, err := verifyCompoundTx(app.db, req.Tx)
- if err == nil {
- // ---- Валидация содержимого композита по ER ----
- p := compound.Body.Promise
- c := compound.Body.Commitment
-
- // Оба тела должны присутствовать
- if p == nil || c == nil {
- return abci.ResponseCheckTx{Code: 1, Log: "compound must include promise and commitment"}
- }
-
- // ID-предикаты и префиксы
- if err := requireIDPrefix(p.ID, "promise"); err != nil {
- return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- }
- if err := requireIDPrefix(c.ID, "commitment"); err != nil {
- return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- }
- if err := requireIDPrefix(c.CommiterID, "commiter"); err != nil {
- return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- }
- //if err := requireIDPrefix(p.BeneficiaryID, "beneficiary"); err != nil {
- // return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- //}
- if p.ParentPromiseID != nil {
- if err := requireIDPrefix(*p.ParentPromiseID, "promise"); err != nil {
- return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- }
- if *p.ParentPromiseID == p.ID {
- return abci.ResponseCheckTx{Code: 2, Log: "parent_promise_id must not equal promise id"}
+ // Проверяем, существует ли уже такая запись
+ err := app.db.View(func(txn *badger.Txn) error {
+ item, err := txn.Get(key)
+ if err != nil {
+ if err == badger.ErrKeyNotFound {
+ return nil // ключ не найден, все ок
}
+ return err
}
- // Базовые обязательные поля Promise
- if strings.TrimSpace(p.Text) == "" {
- return abci.ResponseCheckTx{Code: 2, Log: "promise.text is required"}
- }
- //if p.Due == 0 {
- // return abci.ResponseCheckTx{Code: 2, Log: "promise.due is required"}
- //}
- // Commitment due
- //if c.Due == 0 {
- // return abci.ResponseCheckTx{Code: 2, Log: "commitment.due is required"}
- //}
-
- // Связность по ER
- if c.PromiseID != p.ID {
- return abci.ResponseCheckTx{Code: 2, Log: "commitment.promise_id must equal promise.id"}
- }
-
- // Уникальность Promise.ID
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(p.ID))
- if e == badger.ErrKeyNotFound {
- return nil
- }
- return errors.New("duplicate promise ID")
- }); err != nil {
- return abci.ResponseCheckTx{Code: 3, Log: err.Error()}
- }
- // Уникальность Commitment.ID
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(c.ID))
- if e == badger.ErrKeyNotFound {
- return nil
- }
- return errors.New("duplicate commitment ID")
- }); err != nil {
- return abci.ResponseCheckTx{Code: 3, Log: err.Error()}
- }
-
- // Существование коммитера
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(c.CommiterID))
- if e == badger.ErrKeyNotFound {
- return errors.New("unknown commiter")
+ return item.Value(func(val []byte) error {
+ if bytes.Equal(val, value) {
+ return fmt.Errorf("duplicate key-value")
}
return nil
- }); err != nil {
- return abci.ResponseCheckTx{Code: 4, Log: err.Error()}
- }
+ })
+ })
- // Существование бенефициара
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(p.BeneficiaryID))
- if e == badger.ErrKeyNotFound {
- return errors.New("unknown beneficiary")
- }
- return nil
- }); err != nil {
- return abci.ResponseCheckTx{Code: 5, Log: err.Error()}
+ if err != nil {
+ if err.Error() == "duplicate key-value" {
+ return 2 // дубликат найден
}
-
- // Существование parent (если задан)
- if p.ParentPromiseID != nil {
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(*p.ParentPromiseID))
- if e == badger.ErrKeyNotFound {
- return errors.New("unknown parent promise")
- }
- return nil
- }); err != nil {
- return abci.ResponseCheckTx{Code: 6, Log: err.Error()}
- }
- }
-
- return abci.ResponseCheckTx{Code: 0}
+ // любая другая ошибка
+ return 1
}
- // ---- Попытка ОДИНОЧНЫХ транзакций ----
-
- // 3.1) Совместимость: одиночный commiter (твоя старая логика)
- if body, oldErr := verifyAndExtractBody(app.db, req.Tx); oldErr == nil {
- id, ok := body["id"].(string)
- if !ok || id == "" {
- return abci.ResponseCheckTx{Code: 2, Log: "missing id"}
- }
- if err := requireIDPrefix(id, "commiter"); err != nil {
- return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- }
- // Дубликат
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(id))
- if e == badger.ErrKeyNotFound {
- return nil
- }
- return errors.New("duplicate id")
- }); err != nil {
- return abci.ResponseCheckTx{Code: 3, Log: err.Error()}
- }
- return abci.ResponseCheckTx{Code: 0}
- }
-
- var single struct {
- Body types.BeneficiaryTxBody `json:"body"`
- Signature string `json:"signature"`
- }
- if err2 := json.Unmarshal(req.Tx, &single); err2 == nil && single.Body.Type == "beneficiary" {
- if err := requireIDPrefix(single.Body.ID, "beneficiary"); err != nil {
- return abci.ResponseCheckTx{Code: 2, Log: err.Error()}
- }
- if strings.TrimSpace(single.Body.Name) == "" {
- return abci.ResponseCheckTx{Code: 2, Log: "beneficiary.name is required"}
- }
- // уникальность
- if err := app.db.View(func(txn *badger.Txn) error {
- _, e := txn.Get([]byte(single.Body.ID))
- if e == badger.ErrKeyNotFound {
- return nil
- }
- return errors.New("duplicate beneficiary ID")
- }); err != nil {
- return abci.ResponseCheckTx{Code: 3, Log: err.Error()}
- }
- return abci.ResponseCheckTx{Code: 0}
- }
-
- // Если дошли сюда — составной формат не прошёл; вернём его причину.
- return abci.ResponseCheckTx{Code: 1, Log: err.Error()}
+ return 0 // все проверки пройдены
}
-func (app *PromiseApp) BeginBlock(_ abci.RequestBeginBlock) abci.ResponseBeginBlock {
+func (app *KVStoreApplication) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
+ code := app.isValid(req.Tx)
+ return abci.ResponseCheckTx{Code: code, GasWanted: 1}
+}
+
+// Начало блока
+func (app *KVStoreApplication) BeginBlock(req abci.RequestBeginBlock) abci.ResponseBeginBlock {
+ // If there's an existing batch for some reason, discard it first
if app.currentBatch != nil {
app.currentBatch.Discard()
}
@@ -262,222 +69,112 @@ func (app *PromiseApp) BeginBlock(_ abci.RequestBeginBlock) abci.ResponseBeginBl
return abci.ResponseBeginBlock{}
}
-func (app *PromiseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {
- // Попытка композита
- if compound, err := verifyCompoundTx(app.db, req.Tx); err == nil {
- if app.currentBatch == nil {
- app.currentBatch = app.db.NewTransaction(true)
- }
- if compound.Body.Promise != nil {
- data, _ := json.Marshal(compound.Body.Promise)
- if err := app.currentBatch.Set([]byte(compound.Body.Promise.ID), data); err != nil {
- return abci.ResponseDeliverTx{Code: 1, Log: "failed to save promise"}
- }
- }
- if compound.Body.Commitment != nil {
- data, _ := json.Marshal(compound.Body.Commitment)
- if err := app.currentBatch.Set([]byte(compound.Body.Commitment.ID), data); err != nil {
- return abci.ResponseDeliverTx{Code: 1, Log: "failed to save commitment"}
- }
- }
- return abci.ResponseDeliverTx{Code: 0}
+// Применение транзакции
+func (app *KVStoreApplication) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx {
+ code := app.isValid(req.Tx)
+ if code != 0 {
+ return abci.ResponseDeliverTx{Code: code}
}
- // Одиночный commiter (как раньше)
- {
- var outer struct {
- Body types.CommiterTxBody `json:"body"`
- Signature string `json:"signature"`
- }
- if err := json.Unmarshal(req.Tx, &outer); err == nil && outer.Body.Type == "commiter" {
- // сигнатуру проверяем прежней функцией
- if _, vErr := verifyAndExtractBody(app.db, req.Tx); vErr != nil {
- return abci.ResponseDeliverTx{Code: 1, Log: vErr.Error()}
- }
- if app.currentBatch == nil {
- app.currentBatch = app.db.NewTransaction(true)
- }
- data, _ := json.Marshal(outer.Body)
- if err := app.currentBatch.Set([]byte(outer.Body.ID), data); err != nil {
- return abci.ResponseDeliverTx{Code: 1, Log: err.Error()}
- }
- return abci.ResponseDeliverTx{Code: 0}
+ parts := bytes.Split(req.Tx, []byte("="))
+ if app.currentBatch == nil {
+ // In case BeginBlock wasn't called or batch was discarded
+ app.currentBatch = app.db.NewTransaction(true)
+ }
+
+ err := app.currentBatch.Set(parts[0], parts[1])
+ if err != nil {
+ return abci.ResponseDeliverTx{
+ Code: 1,
+ Log: fmt.Sprintf("Failed to set key: %v", err),
}
}
- // Одиночный beneficiary
- {
- var outer struct {
- Body types.BeneficiaryTxBody `json:"body"`
- Signature string `json:"signature"`
- }
- if err := json.Unmarshal(req.Tx, &outer); err == nil && outer.Body.Type == "beneficiary" {
- // (пока без проверки подписи — можно добавить политику позже)
- if app.currentBatch == nil {
- app.currentBatch = app.db.NewTransaction(true)
- }
- data, _ := json.Marshal(outer.Body)
- if err := app.currentBatch.Set([]byte(outer.Body.ID), data); err != nil {
- return abci.ResponseDeliverTx{Code: 1, Log: err.Error()}
- }
- return abci.ResponseDeliverTx{Code: 0}
- }
- }
-
- return abci.ResponseDeliverTx{Code: 1, Log: "invalid tx format"}
+ return abci.ResponseDeliverTx{Code: 0}
}
-func verifyCompoundTx(db *badger.DB, tx []byte) (*types.CompoundTx, error) {
- // 1) Разобрать внешний конверт, body оставить сырым
- var outerRaw compoundTxRaw
- if err := json.Unmarshal(tx, &outerRaw); err != nil {
- return nil, errors.New("invalid compound tx JSON")
- }
- if len(outerRaw.Body) == 0 {
- return nil, errors.New("missing body")
- }
-
- // 2) Вынуть commiter_id из body, не парся всё
- var tiny struct {
- Commitment *struct {
- CommiterID string `json:"commiter_id"`
- } `json:"commitment"`
- }
- if err := json.Unmarshal(outerRaw.Body, &tiny); err != nil {
- return nil, errors.New("invalid body JSON")
- }
- if tiny.Commitment == nil || strings.TrimSpace(tiny.Commitment.CommiterID) == "" {
- return nil, errors.New("missing commitment")
- }
- commiterID := tiny.Commitment.CommiterID
-
- // 3) Достать коммитера из БД и получить публичный ключ
- var commiterData []byte
- err := db.View(func(txn *badger.Txn) error {
- item, err := txn.Get([]byte(commiterID))
- if err != nil {
- return errors.New("unknown commiter")
- }
- return item.Value(func(v []byte) error {
- commiterData = append([]byte{}, v...)
- return nil
- })
- })
- if err != nil {
- return nil, err
- }
- var commiter types.CommiterTxBody
- if err := json.Unmarshal(commiterData, &commiter); err != nil {
- return nil, errors.New("corrupted commiter record")
- }
- pubkeyB64 := strings.TrimSpace(commiter.CommiterPubKey)
- if pubkeyB64 == "" {
- return nil, errors.New("missing commiter pubkey")
- }
- pubkey, err := base64.StdEncoding.DecodeString(pubkeyB64)
- if err != nil {
- return nil, errors.New("invalid pubkey base64")
- }
- if len(pubkey) != ed25519.PublicKeySize {
- return nil, fmt.Errorf("invalid pubkey length: got %d, want %d", len(pubkey), ed25519.PublicKeySize)
- }
-
- // 4) Проверка подписи над СЫРЫМИ БАЙТАМИ body (как клиент подписывал)
- sig, err := base64.StdEncoding.DecodeString(outerRaw.Signature)
- if err != nil {
- return nil, errors.New("invalid signature base64")
- }
- if len(sig) != ed25519.SignatureSize {
- return nil, fmt.Errorf("invalid signature length: got %d, want %d", len(sig), ed25519.SignatureSize)
- }
- if !ed25519.Verify(pubkey, outerRaw.Body, sig) {
- return nil, errors.New("signature verification failed")
- }
-
- // 5) Только после успешной проверки — распарсить body в наши структуры
- var body compoundBody
- if err := json.Unmarshal(outerRaw.Body, &body); err != nil {
- return nil, errors.New("invalid body JSON")
- }
-
- // 6) Вернуть в привычной форме
- return &types.CompoundTx{
- Body: struct {
- Promise *types.PromiseTxBody `json:"promise"`
- Commitment *types.CommitmentTxBody `json:"commitment"`
- }{
- Promise: body.Promise,
- Commitment: body.Commitment,
- },
- Signature: outerRaw.Signature,
- }, nil
-}
-
-func (app *PromiseApp) Commit() abci.ResponseCommit {
+// Завершение блока и фиксация
+func (app *KVStoreApplication) Commit() abci.ResponseCommit {
if app.currentBatch != nil {
err := app.currentBatch.Commit()
if err != nil {
- fmt.Printf("Commit error: %v\n", err)
+ // Log error but continue - in a real application, you might want
+ // to handle this more gracefully
+ fmt.Printf("Error committing batch: %v\n", err)
}
app.currentBatch = nil
}
return abci.ResponseCommit{Data: []byte{}}
}
-func (app *PromiseApp) Query(req abci.RequestQuery) abci.ResponseQuery {
- parts := strings.Split(strings.Trim(req.Path, "/"), "/")
- if len(parts) != 2 || parts[0] != "list" {
- return abci.ResponseQuery{Code: 1, Log: "unsupported query"}
- }
- prefix := []byte(parts[1] + ":")
+// Обслуживание запросов Query
+func (app *KVStoreApplication) Query(req abci.RequestQuery) abci.ResponseQuery {
+ resp := abci.ResponseQuery{Code: 0}
- var result []json.RawMessage
err := app.db.View(func(txn *badger.Txn) error {
- it := txn.NewIterator(badger.DefaultIteratorOptions)
- defer it.Close()
- for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
- item := it.Item()
- err := item.Value(func(v []byte) error {
- var raw json.RawMessage = make([]byte, len(v))
- copy(raw, v)
- result = append(result, raw)
- return nil
- })
- if err != nil {
- return err
- }
+ item, err := txn.Get(req.Data)
+ if err != nil {
+ return err
}
- return nil
+
+ return item.Value(func(val []byte) error {
+ resp.Value = val
+ return nil
+ })
})
if err != nil {
- return abci.ResponseQuery{Code: 1, Log: err.Error()}
+ resp.Code = 1
+ resp.Log = err.Error()
}
- all, _ := json.Marshal(result)
- return abci.ResponseQuery{Code: 0, Value: all}
+
+ return resp
}
-func (app *PromiseApp) Info(req abci.RequestInfo) abci.ResponseInfo {
- return abci.ResponseInfo{Data: "promises", Version: "0.1"}
+// Добавляем недостающие методы ABCI интерфейса
+
+// Info возвращает информацию о приложении
+func (app *KVStoreApplication) Info(req abci.RequestInfo) abci.ResponseInfo {
+ return abci.ResponseInfo{
+ Data: "kvstore",
+ Version: "1.0.0",
+ AppVersion: 1,
+ LastBlockHeight: 0,
+ LastBlockAppHash: []byte{},
+ }
}
-func (app *PromiseApp) SetOption(req abci.RequestSetOption) abci.ResponseSetOption {
- return abci.ResponseSetOption{}
+
+// SetOption устанавливает опцию приложения
+func (app *KVStoreApplication) SetOption(req abci.RequestSetOption) abci.ResponseSetOption {
+ return abci.ResponseSetOption{Code: 0}
}
-func (app *PromiseApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
+
+// InitChain инициализирует блокчейн
+func (app *KVStoreApplication) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
return abci.ResponseInitChain{}
}
-func (app *PromiseApp) EndBlock(req abci.RequestEndBlock) abci.ResponseEndBlock {
+
+// EndBlock сигнализирует о конце блока
+func (app *KVStoreApplication) EndBlock(req abci.RequestEndBlock) abci.ResponseEndBlock {
return abci.ResponseEndBlock{}
}
-func (app *PromiseApp) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseListSnapshots {
+
+// ListSnapshots возвращает список доступных снапшотов
+func (app *KVStoreApplication) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseListSnapshots {
return abci.ResponseListSnapshots{}
}
-func (app *PromiseApp) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot {
+
+// OfferSnapshot предлагает снапшот приложению
+func (app *KVStoreApplication) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot {
return abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_REJECT}
}
-func (app *PromiseApp) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.ResponseLoadSnapshotChunk {
+
+// LoadSnapshotChunk загружает часть снапшота
+func (app *KVStoreApplication) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.ResponseLoadSnapshotChunk {
return abci.ResponseLoadSnapshotChunk{}
}
-func (app *PromiseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.ResponseApplySnapshotChunk {
+
+// ApplySnapshotChunk применяет часть снапшота
+func (app *KVStoreApplication) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.ResponseApplySnapshotChunk {
return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}
}
diff --git a/blockchain/main.go b/blockchain/main.go
index e80d8a4..092d159 100644
--- a/blockchain/main.go
+++ b/blockchain/main.go
@@ -4,10 +4,9 @@ import (
"context"
"fmt"
+ "lbc/cfg"
"os"
- "github.com/gregorybednov/lbc/cfg"
-
"github.com/dgraph-io/badger"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
@@ -24,7 +23,6 @@ func openBadger(path string) (*badger.DB, error) {
func newTendermint(app abci.Application, config *cfg.Config, laddrReturner chan string) (*nm.Node, error) {
config.P2P.ListenAddress = "tcp://" + <-laddrReturner
- config.P2P.ExternalAddress = <-laddrReturner
config.P2P.PersistentPeers = <-laddrReturner
var pv tmTypes.PrivValidator
@@ -65,7 +63,7 @@ func GetNodeInfo(config *cfg.Config, dbPath string) (p2p.NodeInfo, error) {
}
defer db.Close()
- app := NewPromiseApp(db)
+ app := NewKVStoreApplication(db)
nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile())
if err != nil {
@@ -112,7 +110,7 @@ func Run(ctx context.Context, dbPath string, config *cfg.Config, laddrReturner c
}
defer db.Close()
- app := NewPromiseApp(db)
+ app := NewKVStoreApplication(db)
node, err := newTendermint(app, config, laddrReturner)
if err != nil {
return fmt.Errorf("build node: %w", err)
diff --git a/cfg/configfunctions.go b/cfg/configfunctions.go
index befb37d..b4705d9 100644
--- a/cfg/configfunctions.go
+++ b/cfg/configfunctions.go
@@ -6,13 +6,12 @@ import (
"flag"
"fmt"
"io"
+ "lbc/yggdrasil"
"os"
"path/filepath"
"strconv"
"time"
- "github.com/gregorybednov/lbc/yggdrasil"
-
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
@@ -164,17 +163,16 @@ func WriteConfig(config *cfg.Config, configPath *string, nodeInfo p2p.NodeInfo)
config.P2P.PersistentPeers = a
}
- v.Set("p2p", map[string]any{
- "use_legacy": false,
- "queue_type": "priority",
- "laddr": strconv.Itoa(yggListenPort) + ":127.0.0.1:8000",
- "external_address": "",
- "upnp": false,
- "bootstrap_peers": "",
- "persistent_peers": config.P2P.PersistentPeers,
- "allow_duplicate_ip": true, // needed because of Yggdrasil proxy
- "addr_book_file": "config/addrbook.json",
- "addr_book_strict": false,
+ v.Set("p2p", map[string]interface{}{
+ "use_legacy": false,
+ "queue_type": "priority",
+ "laddr": strconv.Itoa(yggListenPort) + ":127.0.0.1:8000",
+ "external_address": "", // will be set automatically by Tendermint if needed
+ "upnp": false,
+ "bootstrap_peers": "",
+ "persistent_peers": config.P2P.PersistentPeers,
+ "addr_book_file": "config/addrbook.json",
+ "addr_book_strict": false,
})
err = v.WriteConfigAs(*configPath)
@@ -252,25 +250,18 @@ func UpdateGenesisJson(nodeInfo p2p.NodeInfo, v *viper.Viper, defaultConfigDirec
}
}
-func InitGenesis(chainName, defaultConfigPath string) (*cfg.Config, *viper.Viper, error) {
+func InitGenesis(chainName, defaultConfigPath string) (*cfg.Config, *viper.Viper) {
config := cfg.DefaultConfig()
config.RootDir = filepath.Dir(filepath.Dir(defaultConfigPath))
- if err := os.MkdirAll(config.RootDir, 0o755); err != nil {
- return nil, nil, fmt.Errorf("failed to create config directory %s: %w", config.RootDir, err)
- }
- if err := os.MkdirAll(filepath.Dir(defaultConfigPath), 0o755); err != nil {
- return nil, nil, fmt.Errorf("failed to create config directory %s: %w", filepath.Dir(defaultConfigPath), err)
- }
-
nodeinfo := p2p.DefaultNodeInfo{}
viper := WriteConfig(config, &defaultConfigPath, nodeinfo)
-
if err := InitTendermintFiles(config, true, chainName); err != nil {
- return nil, nil, fmt.Errorf("failed to init tendermint files: %w", err)
+ fmt.Fprintf(os.Stderr, "Failed to init files: %v\n", err)
+ panic(err)
}
- return config, viper, nil
+ return config, viper
}
func InitJoiner(chainName, defaultConfigPath, path string) error {
diff --git a/cli/init.go b/cli/init.go
index 03c6747..77fab6d 100644
--- a/cli/init.go
+++ b/cli/init.go
@@ -2,12 +2,11 @@ package cli
import (
"fmt"
+ "lbc/blockchain"
+ "lbc/cfg"
"os"
"path/filepath"
- "github.com/gregorybednov/lbc/blockchain"
- "github.com/gregorybednov/lbc/cfg"
-
"github.com/spf13/cobra"
)
@@ -18,11 +17,7 @@ var initCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
switch args[0] {
case "genesis":
- config, viper, err := cfg.InitGenesis(chainName, defaultConfigPath)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error: %v", err)
- panic(err)
- }
+ config, viper := cfg.InitGenesis(chainName, defaultConfigPath)
nodeinfo, err := blockchain.GetNodeInfo(config, dbPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v", err)
@@ -34,14 +29,14 @@ var initCmd = &cobra.Command{
case "join":
if len(args) < 2 {
fmt.Fprintln(os.Stderr, "Укажите путь к genesis.json")
- return
+ os.Exit(1)
}
cfg.InitJoiner(chainName, defaultConfigPath, args[1])
fmt.Println("Joiner node initialized.")
default:
fmt.Fprintf(os.Stderr, "Неизвестный режим init: %s\n", args[0])
- return
+ os.Exit(1)
}
},
}
diff --git a/cli/root.go b/cli/root.go
index 303956c..e582de6 100644
--- a/cli/root.go
+++ b/cli/root.go
@@ -3,16 +3,13 @@ package cli
import (
"context"
"fmt"
- "io"
+ "lbc/blockchain"
+ "lbc/cfg"
+ "lbc/yggdrasil"
"os"
"os/signal"
- "path/filepath"
"syscall"
- "github.com/gregorybednov/lbc/blockchain"
- "github.com/gregorybednov/lbc/cfg"
- "github.com/gregorybednov/lbc/yggdrasil"
-
"github.com/spf13/cobra"
)
@@ -44,7 +41,7 @@ var rootCmd = &cobra.Command{
По умолчанию файл конфигурации ищется по пути: %s
`, err, defaultConfigPath)
- return
+ os.Exit(1)
}
config, err := cfg.ReadConfig(defaultConfigPath)
@@ -53,7 +50,7 @@ var rootCmd = &cobra.Command{
}
ctx, cancel := context.WithCancel(context.Background())
- laddrReturner := make(chan string, 3)
+ laddrReturner := make(chan string, 2)
go yggdrasil.Yggdrasil(v, laddrReturner)
go blockchain.Run(ctx, dbPath, config, laddrReturner)
@@ -70,38 +67,6 @@ var rootCmd = &cobra.Command{
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "ошибка: %v\n", err)
- return
+ os.Exit(1)
}
}
-
-func ExecuteWithArgs(args []string, home string, stdout, stderr io.Writer) error {
- // Перенаправляем вывод Cobra
- if stdout != nil {
- rootCmd.SetOut(stdout)
- }
- if stderr != nil {
- rootCmd.SetErr(stderr)
- }
-
- // Если задан home, подставим дефолты, на которые завязаны флаги
- // (флаги привязаны к переменным через StringVar, поэтому смена переменных до Execute — норм.)
- origCfg := defaultConfigPath
- origDB := dbPath
-
- if home != "" {
- defaultConfigPath = filepath.Join(home, "config", "config.toml")
- // Примем convention: BADGER в (home)/data/badger, но если у тебя другое — поменяй строку ниже.
- dbPath = filepath.Join(home, "data", "badger")
- }
-
- // Важное: подаём именно те аргументы, которые хотел вызвать вызывающий код.
- rootCmd.SetArgs(args)
-
- // Выполняем и аккуратно восстанавливаем глобальные дефолты.
- err := rootCmd.Execute()
-
- defaultConfigPath = origCfg
- dbPath = origDB
-
- return err
-}
diff --git a/cli/testyggdrasil.go b/cli/testyggdrasil.go
index eca78be..58f8b01 100644
--- a/cli/testyggdrasil.go
+++ b/cli/testyggdrasil.go
@@ -4,6 +4,8 @@ import (
"context"
"fmt"
"io"
+ "lbc/cfg"
+ "lbc/yggdrasil"
"log"
"net"
"net/url"
@@ -13,9 +15,6 @@ import (
"syscall"
"time"
- "github.com/gregorybednov/lbc/cfg"
- "github.com/gregorybednov/lbc/yggdrasil"
-
"github.com/spf13/cobra"
)
@@ -26,7 +25,7 @@ var testYggdrasilCmd = &cobra.Command{
v, err := cfg.LoadViperConfig(defaultConfigPath)
if err != nil {
fmt.Fprintf(os.Stderr, "не удалось прочитать конфигурацию viper: %v", err)
- return err
+ os.Exit(1)
}
config, err := cfg.ReadConfig(defaultConfigPath)
if err != nil {
diff --git a/docs/ER.svg b/docs/ER.svg
deleted file mode 100644
index 5bec34d..0000000
--- a/docs/ER.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/database_schema.md b/docs/database_schema.md
deleted file mode 100644
index 00ba10c..0000000
--- a/docs/database_schema.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# Логическая модель данных
-
-![[ER.svg]]
-
-
- @startuml
-
- entity Promise {
- * ID: uuid
- --
- * text: string
- due: datetime
- BeneficiaryID: uuid
- ParentPromiseID: uuid
- }
-
- entity Beneficiary {
- * ID: uuid
- --
- * name: string
- }
-
- entity Commitment {
- * ID: uuid
- --
- PromiseID: uuid
- CommiterID: uuid
- due: datetime
- }
-
- entity Commiter {
- * ID: uuid
- --
- * name: string
- }
-
- Commitment }|--|| Promise : belongs to
- Commitment }|--|| Commiter : made by
- Promise }o--|| Beneficiary : has
- Promise }--o Promise : parent of
-
- @enduml
-
diff --git a/go.mod b/go.mod
index 7b3f7b1..e9944ee 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/gregorybednov/lbc
+module lbc
go 1.24.3
@@ -68,7 +68,6 @@ require (
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/pprof v0.0.0-20241017200806-017d972448fc // indirect
github.com/gorilla/websocket v1.5.3 // indirect
- github.com/gregorybednov/lbc_sdk v0.0.0-20250810123844-a90b874431fa // indirect
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
diff --git a/go.sum b/go.sum
index fca1357..fbd0cf5 100644
--- a/go.sum
+++ b/go.sum
@@ -195,10 +195,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gregorybednov/lbc_sdk v0.0.0-20250810102513-432a51e65f76 h1:e3A+1v+Mjt8nuJcVnHuhHZuh4052KRLCUBpH4g74rVs=
-github.com/gregorybednov/lbc_sdk v0.0.0-20250810102513-432a51e65f76/go.mod h1:DBE00+SaYBtD4qw+nOtSTLuF6h9Ia4TkuBMJB+6krik=
-github.com/gregorybednov/lbc_sdk v0.0.0-20250810123844-a90b874431fa h1:8EuqAmsS94ju83o4aEIV8e2fdocdAJ9xVerKRSI+nDA=
-github.com/gregorybednov/lbc_sdk v0.0.0-20250810123844-a90b874431fa/go.mod h1:DBE00+SaYBtD4qw+nOtSTLuF6h9Ia4TkuBMJB+6krik=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
diff --git a/main.go b/main.go
index 5aeb0d8..2e6c6fb 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,7 @@
package main
import (
- "github.com/gregorybednov/lbc/cli"
+ "lbc/cli"
)
func main() {
diff --git a/yggdrasil/main.go b/yggdrasil/main.go
index 4e86711..6d81bbb 100644
--- a/yggdrasil/main.go
+++ b/yggdrasil/main.go
@@ -62,7 +62,7 @@ func Yggdrasil(config *viper.Viper, ch chan string) {
parsed, err := ParseEntries(peers)
if err != nil {
parsed = []ParsedEntry{}
- // ch <- ""
+ ch <- ""
log.Warnln("Warning: persistent peers has an error")
}
@@ -141,18 +141,11 @@ func Yggdrasil(config *viper.Viper, ch chan string) {
panic(err)
}
address, subnet := n.core.Address(), n.core.Subnet()
- yggPort := 26656
- if len(remoteTcp) > 0 && remoteTcp[0].Listen.Port != 0 {
- yggPort = remoteTcp[0].Listen.Port
- }
- ipStr := address.String() // ожидается чистый IPv6 без /префикса
- yggExternal := fmt.Sprintf("[%s]:%d", ipStr, yggPort)
- ch <- yggExternal
-
- //logger.Printf("Your public key is %s", publicstr)
+ publicstr := hex.EncodeToString(n.core.PublicKey())
+ logger.Printf("Your public key is %s", publicstr)
logger.Printf("Your IPv6 address is %s", address.String())
logger.Printf("Your IPv6 subnet is %s", subnet.String())
- //logger.Printf("Your Yggstack resolver name is %s%s", publicstr, types.NameMappingSuffix)
+ logger.Printf("Your Yggstack resolver name is %s%s", publicstr, types.NameMappingSuffix)
}
// Setup the admin socket.