5 Commits

Author SHA1 Message Date
b8089cb0e3 Merge pull request 'dev' (#5) from dev into master
Reviewed-on: https://git.dejodigital.com.br/dejo-core/dejo-node/pulls/5
2025-06-20 23:45:12 +00:00
9265171a5e fiz: remoção da pasta data
Some checks failed
CI & CD / Lint Commits (push) Has been cancelled
CI & CD / Release (push) Has been cancelled
CI & CD / Docker | Build and Push (push) Has been cancelled
CI & CD / Kubernetes | Kustomize Apply (push) Has been cancelled
CI & CD / Kubernetes | Deploy App (push) Has been cancelled
2025-06-17 18:26:57 -03:00
9259f36e9c fiz: correções da pool 2025-06-17 18:26:14 -03:00
682027d517 doc: k8s v.027 para 1.20 2025-06-13 16:45:26 -03:00
7419f66c83 doc: k8s v.027 para 1.20 2025-06-13 16:34:30 -03:00
26 changed files with 294 additions and 301 deletions

5
.env Executable file
View File

@ -0,0 +1,5 @@
NODE_ENV=local
NODE_ID=node1
DEJO_PORT=8080
DEJO_VALIDATORS=node1,node2
DEJO_PEERS=http://localhost:8080,http://localhost:8081

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
# Local .terraform directories # Local .terraform directories
### Terraform ### ### Terraform ###
data
**/.terraform/* **/.terraform/*
*.tfstate *.tfstate
*.tfstate.* *.tfstate.*

View File

@ -1,50 +1,61 @@
# 📦 Changelog - DEJO Node # [1.6.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.5.0...v1.6.0) (2025-06-13)
## ✅ Versão 1.0.0 (Finalizada)
### 🏗️ Estrutura Inicial ### Features
- Organização de diretórios `cmd/`, `internal/`, `pkg/`
- Dockerfile, Makefile e configs prontos
- `main.go` funcional
### 🔐 Transações * teste deploy Upgrade karpenter k8s v.027 para 1.20 ([bff2c0a](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/bff2c0abff5908cd03240c33ef0a6eb4b64b79ff))
- Estrutura básica de TX (`from`, `to`, `value`, `nonce`, `signature`)
- Validações e verificação de assinatura
- Mempool integrada
### 📦 Armazenamento # [1.5.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.4.0...v1.5.0) (2025-06-12)
- Implementação com LevelDB
- Indexação por hash e blocos
### 🌐 Comunicação P2P
- libp2p com detecção automática
- Proteção Sybil (limite de conexões, delay por PeerID)
- Logs de conexões e desconexões
### ⚖️ Consenso ### Features
- Algoritmo mínimo viável tipo PoA/BFT
- Validação e finalização de blocos
### 🔗 API REST * Alteração trigger deploy branch master para dev ([dbe89a5](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/dbe89a5cc4132c867a09827a005436bc538933fd))
- Endpoints: `/tx`, `/tx/{hash}`, `/block/{hash}`, `/mempool` * Alteração trigger deploy branch master para dev ([0ec68b0](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/0ec68b07bc208c59ad5d431cfc89b561cc82991e))
- Health checks: `/health`, `/startup`, `/ready` * Alteração trigger deploy branch master para dev ([8208b46](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/8208b46622afda1aa2c052547cb5273b6c0c0639))
* Alteração trigger deploy branch master para dev ([70d8fe4](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/70d8fe490602a3a1bc9f0fd9f6011678f9b7f875))
* Alteração trigger deploy branch master para dev ([6363e7a](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/6363e7a9d59f01c0b6b5bd2f024a63aedfd954bb))
* Alteração trigger deploy branch master para dev ([15bb087](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/15bb0872f818e2a7868b87ee53ed8fbbeafa1322))
* Alteração trigger deploy branch master para dev ([1b2aaff](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/1b2aaff753dfd3da0ceb616446607ad4823676fe))
* Alteração trigger deploy branch master para dev ([772a1ac](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/772a1ac9e91200666e41211e2c264eb70e214b39))
* resolve conflitos em CHANGELOG.md após merge de master ([f9fca8c](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/f9fca8c0a00af28c7905ad3a3ca03d55bb5ce714))
### 🗳️ Governança # [1.3.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.2.0...v1.3.0) (2025-06-11)
- Estrutura de staking e votação
- RPCs para propostas e eleição
### 🛰️ Oráculos
- Placeholder e endpoint para feed externo validado
### 🔐 Segurança ### Features
- Rate Limiting anti-DDoS
- Monitoramento de conexões suspeitas
- Modularização para reputação de peer
### 📊 DevOps * Alteração trigger deploy branch master para dev ([13b7ccb](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/13b7ccb1bf718b16dcad3dd81fe4e8cb9dd2a31c))
- `/metrics` com Prometheus (`tx_total`, `uptime`)
- `openapi.yaml` com documentação completa
--- # [1.2.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.1.0...v1.2.0) (2025-06-11)
🚀 Projeto DEJO Node pronto para produção modular!
### Features
* Alteração trigger deploy branch master para dev ([84a35b0](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/84a35b08a157a50edaddb87cacf1ec585e7f2b5d))
# [1.1.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.0.0...v1.1.0) (2025-06-11)
### Features
* Alteração trigger deploy branch master para dev ([6f88c7a](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/6f88c7a2b86899fed822aa42c8c1dd9720865fef))
* Alteração trigger deploy branch master para dev ([2340355](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/2340355e6cbe57bcd52d9b038f4661f03d3c0401))
* Alteração trigger deploy branch master para dev ([43acc8f](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/43acc8f809ffcb75e4b9f3cb1e5199a572900c6a))
# 1.0.0 (2025-06-11)
### Features
<<<<<<< HEAD
* Alteração trigger deploy branch master para dev ([15bb087](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/15bb0872f818e2a7868b87ee53ed8fbbeafa1322))
* Alteração trigger deploy branch master para dev ([1b2aaff](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/1b2aaff753dfd3da0ceb616446607ad4823676fe))
* Alteração trigger deploy branch master para dev ([772a1ac](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/772a1ac9e91200666e41211e2c264eb70e214b39))
=======
>>>>>>> 4ef86c0 (chore(release): 1.0.0 [skip ci])
=======
>>>>>>> master
* CI/CD - Conventional Commits e Semantic Release ([2c1f871](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/2c1f8715dde4084a08117bffae1bbc40e7b9a95c))
* CI/CD - Conventional Commits e Semantic Release ([cc93db0](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/cc93db0d9a8e1358ca1e3e6128d1d710fc35e5b6))
* CI/CD - Conventional Commits e Semantic Release ([abf3c77](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/abf3c771e539afa48de8139ed7adb81341e80600))

View File

@ -4,13 +4,11 @@ import (
"context" "context"
"dejo_node/internal/api" "dejo_node/internal/api"
"dejo_node/internal/consensus" "dejo_node/internal/consensus"
"dejo_node/internal/mempool"
"dejo_node/internal/monitor"
"dejo_node/internal/staking" "dejo_node/internal/staking"
"dejo_node/internal/state"
"dejo_node/internal/storage" "dejo_node/internal/storage"
"dejo_node/internal/transactions" "dejo_node/internal/transactions"
"fmt" "fmt"
"log"
"net/http" "net/http"
"os" "os"
"strings" "strings"
@ -22,33 +20,52 @@ func main() {
nodeID := os.Getenv("NODE_ID") nodeID := os.Getenv("NODE_ID")
port := os.Getenv("DEJO_PORT") port := os.Getenv("DEJO_PORT")
validators := strings.Split(os.Getenv("DEJO_VALIDATORS"), ",")
peers := strings.Split(os.Getenv("DEJO_PEERS"), ",")
blockStore := storage.NewBlockStore() blockStore := storage.NewBlockStore("./data/blocks")
stakingStore := staking.NewStakingStore() stakingStore := staking.NewStakingStore()
mp := mempool.NewMempool()
globalState := state.NewState()
// Heartbeat function // Carregar staking existente se disponível
pingPeer := func(peer string) bool { if err := stakingStore.LoadFromDisk("./data/staking.db"); err != nil {
client := http.Client{Timeout: 2 * time.Second} fmt.Println(" Criando novo staking store")
resp, err := client.Get(peer + "/health")
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
} }
monitor := monitor.NewMonitor(pingPeer) // Registrar todos os validadores com stake mínimo
minStake := uint64(1000)
validators := strings.Split(os.Getenv("DEJO_VALIDATORS"), ",")
for _, validator := range validators {
if err := stakingStore.Stake(validator, minStake, 1000); err != nil {
panic(err)
}
}
handler := api.NewHandler(blockStore, stakingStore, mp, globalState) mp := transactions.NewMempool()
handler := api.NewHandler()
handler.SetStores(blockStore, stakingStore, mp)
server := api.NewServer(handler) server := api.NewServer(handler)
go func() { go func() {
fmt.Printf("🌐 Servidor HTTP iniciado na porta :%s\n", port) addr := ":" + port
http.ListenAndServe(":"+port, server) fmt.Printf("🌐 Iniciando servidor HTTP em %s\n", addr)
// Adicionar pequeno delay para garantir que tudo está inicializado
time.Sleep(100 * time.Millisecond)
// Verificar se o servidor está respondendo
go func() {
time.Sleep(2 * time.Second) // Aumentar tempo de espera
client := http.Client{Timeout: 2 * time.Second}
resp, err := client.Get("http://localhost" + addr + "/ping")
if err != nil || resp == nil || resp.StatusCode != http.StatusOK {
log.Printf("⚠️ Aviso: Servidor HTTP pode não estar respondendo - %v", err)
return // Não encerrar o programa, apenas registrar o aviso
}
resp.Body.Close()
}()
if err := http.ListenAndServe(addr, server); err != nil {
log.Fatalf("❌ Falha ao iniciar servidor HTTP: %v", err)
}
}() }()
round := consensus.NewRoundState(1) round := consensus.NewRoundState(1)
@ -58,16 +75,16 @@ func main() {
ctx, ctx,
nodeID, nodeID,
round, round,
transport.Receive, transport.Broadcast,
700, 700,
blockStore, blockStore,
func() *transactions.Block { func() *transactions.Block {
return &transactions.Block{ return &transactions.Block{
Txns: mp.GetTransactions(), Txns: mp.All(),
} }
}, },
stakingStore, stakingStore,
globalState, 1000, // minStake
monitor, &consensus.LivenessMonitor{},
) )
} }

View File

@ -1,8 +0,0 @@
{
"Index": 1,
"PrevHash": "genesis",
"Txns": [],
"Timestamp": 1746203588,
"Nonce": 0,
"Hash": "176b199bd82d6e6d22719cdc95709646433204f299b2f49efbba9985ee9eac4e"
}

View File

@ -1,8 +0,0 @@
{
"Index": 2,
"PrevHash": "176b199bd82d6e6d22719cdc95709646433204f299b2f49efbba9985ee9eac4e",
"Txns": [],
"Timestamp": 1746203596,
"Nonce": 0,
"Hash": "0af7272a293becc055d79604b96717e06be4e3ff8be65f1d65b6d1979b9d166c"
}

View File

@ -1,8 +0,0 @@
{
"Index": 3,
"PrevHash": "0af7272a293becc055d79604b96717e06be4e3ff8be65f1d65b6d1979b9d166c",
"Txns": [],
"Timestamp": 1746206836,
"Nonce": 0,
"Hash": "40186b92c0be8c1cd252b223dce51df3156a3fadd32e21f38db298e01da70f69"
}

View File

@ -1,8 +0,0 @@
{
"Index": 4,
"PrevHash": "40186b92c0be8c1cd252b223dce51df3156a3fadd32e21f38db298e01da70f69",
"Txns": [],
"Timestamp": 1746206844,
"Nonce": 0,
"Hash": "4519522e80850a467c571eccdbad3a9b078b75d0dd3c889a87725c207eff3464"
}

Binary file not shown.

Binary file not shown.

6
go.mod
View File

@ -11,8 +11,6 @@ require (
github.com/libp2p/go-libp2p-kad-dht v0.30.2 github.com/libp2p/go-libp2p-kad-dht v0.30.2
github.com/multiformats/go-multiaddr v0.15.0 github.com/multiformats/go-multiaddr v0.15.0
github.com/prometheus/client_golang v1.21.1 github.com/prometheus/client_golang v1.21.1
github.com/stretchr/testify v1.10.0
github.com/syndtr/goleveldb v1.0.0
github.com/ulule/limiter/v3 v3.11.2 github.com/ulule/limiter/v3 v3.11.2
go.uber.org/zap v1.27.0 go.uber.org/zap v1.27.0
) )
@ -23,7 +21,6 @@ require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
@ -35,7 +32,6 @@ require (
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/gopacket v1.1.19 // indirect github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
@ -104,7 +100,6 @@ require (
github.com/pion/turn/v4 v4.0.0 // indirect github.com/pion/turn/v4 v4.0.0 // indirect
github.com/pion/webrtc/v4 v4.0.10 // indirect github.com/pion/webrtc/v4 v4.0.10 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.89.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/common v0.62.0 // indirect
@ -134,6 +129,5 @@ require (
golang.org/x/tools v0.30.0 // indirect golang.org/x/tools v0.30.0 // indirect
gonum.org/v1/gonum v0.15.1 // indirect gonum.org/v1/gonum v0.15.1 // indirect
google.golang.org/protobuf v1.36.5 // indirect google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.4.0 // indirect lukechampine.com/blake3 v1.4.0 // indirect
) )

16
go.sum
View File

@ -54,7 +54,6 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
@ -81,8 +80,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@ -112,7 +109,6 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/ipfs/boxo v0.28.0 h1:io6nXqN8XMOstB7dQGG5GWnMk4WssoMvva9OADErZdI= github.com/ipfs/boxo v0.28.0 h1:io6nXqN8XMOstB7dQGG5GWnMk4WssoMvva9OADErZdI=
@ -245,15 +241,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@ -384,8 +373,6 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA=
github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI= github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI=
@ -604,10 +591,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -3,6 +3,7 @@ package api
import ( import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@ -12,7 +13,7 @@ func (h *Handler) ListBlocks(w http.ResponseWriter, r *http.Request) {
WriteError(w, http.StatusInternalServerError, "Erro ao listar blocos") WriteError(w, http.StatusInternalServerError, "Erro ao listar blocos")
return return
} }
WriteJSON(w, blocks) WriteJSON(w, http.StatusOK, blocks)
} }
func (h *Handler) GetBlockByHeight(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetBlockByHeight(w http.ResponseWriter, r *http.Request) {
@ -27,5 +28,5 @@ func (h *Handler) GetBlockByHeight(w http.ResponseWriter, r *http.Request) {
WriteError(w, http.StatusNotFound, "Bloco não encontrado") WriteError(w, http.StatusNotFound, "Bloco não encontrado")
return return
} }
WriteJSON(w, block) WriteJSON(w, http.StatusOK, block)
} }

View File

@ -5,8 +5,9 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"github.com/gorilla/mux"
"dejo_node/internal/dao" "dejo_node/internal/dao"
"github.com/gorilla/mux"
) )
type CreateProposalRequest struct { type CreateProposalRequest struct {
@ -30,7 +31,7 @@ func (h *Handler) CreateProposal(w http.ResponseWriter, r *http.Request) {
} }
p := DaoStore.Create(req.Title, req.Content, req.Creator, dao.ProposalType(req.Type), req.Duration) p := DaoStore.Create(req.Title, req.Content, req.Creator, dao.ProposalType(req.Type), req.Duration)
_ = DaoStore.SaveToDisk("data/proposals.db") _ = DaoStore.SaveToDisk("data/proposals.db")
WriteJSON(w, p) WriteJSON(w, http.StatusOK, p)
} }
func (h *Handler) VoteProposal(w http.ResponseWriter, r *http.Request) { func (h *Handler) VoteProposal(w http.ResponseWriter, r *http.Request) {
@ -53,7 +54,7 @@ func (h *Handler) VoteProposal(w http.ResponseWriter, r *http.Request) {
_ = p.Vote(req.Address, req.Approve) _ = p.Vote(req.Address, req.Approve)
p.CheckAndClose(h.snapshotStakes()) p.CheckAndClose(h.snapshotStakes())
_ = DaoStore.SaveToDisk("data/proposals.db") _ = DaoStore.SaveToDisk("data/proposals.db")
WriteJSON(w, p) WriteJSON(w, http.StatusOK, p)
} }
func (h *Handler) GetProposal(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetProposal(w http.ResponseWriter, r *http.Request) {
@ -68,11 +69,11 @@ func (h *Handler) GetProposal(w http.ResponseWriter, r *http.Request) {
WriteError(w, http.StatusNotFound, "Proposta não encontrada") WriteError(w, http.StatusNotFound, "Proposta não encontrada")
return return
} }
WriteJSON(w, p) WriteJSON(w, http.StatusOK, p)
} }
func (h *Handler) ListProposals(w http.ResponseWriter, r *http.Request) { func (h *Handler) ListProposals(w http.ResponseWriter, r *http.Request) {
WriteJSON(w, DaoStore.List()) WriteJSON(w, http.StatusOK, DaoStore.List())
} }
func (h *Handler) snapshotStakes() map[string]uint64 { func (h *Handler) snapshotStakes() map[string]uint64 {

View File

@ -1,20 +1,33 @@
package api package api
import ( import (
"dejo_node/internal/mempool"
"dejo_node/internal/staking" "dejo_node/internal/staking"
"dejo_node/internal/storage" "dejo_node/internal/storage"
"dejo_node/internal/transactions"
"net/http"
) )
type Handler struct { type Handler struct {
Store *storage.BlockStore Store *storage.BlockStore
StakingStore *staking.StakingStore StakingStore *staking.StakingStore
Mempool *mempool.Mempool Mempool *transactions.Mempool
} }
func NewHandler() *Handler { func NewHandler() *Handler {
return &Handler{ return &Handler{}
Store: storage.NewBlockStore("data/blocks.json"), }
StakingStore: staking.NewStakingStore(),
} func (h *Handler) SetStores(blockStore *storage.BlockStore, stakingStore *staking.StakingStore, mempool *transactions.Mempool) {
h.Store = blockStore
h.StakingStore = stakingStore
h.Mempool = mempool
}
func (h *Handler) Ping(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("pong"))
}
func (h *Handler) HandleConsensus(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
} }

View File

@ -2,9 +2,10 @@ package api
import ( import (
"net/http" "net/http"
"time"
) )
func (h *Handler) Health(w http.ResponseWriter, r *http.Request) { func (h *Handler) Health(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("ok")) w.Write([]byte(time.Now().Format(time.RFC3339)))
} }

View File

@ -2,41 +2,25 @@ package api
import ( import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
"net/http"
) )
func NewRouter(h *Handler) http.Handler { func (h *Handler) RegisterRoutes(r *mux.Router) {
r := mux.NewRouter() // Rotas de blocos
r.HandleFunc("/health", h.Health).Methods("GET")
r.HandleFunc("/startup", h.Startup).Methods("GET")
r.HandleFunc("/ready", h.Ready).Methods("GET")
// ⚡ Transações
r.HandleFunc("/transaction", h.SendTransaction).Methods("POST")
r.HandleFunc("/transaction/{hash}", h.GetTransactionByHash).Methods("GET")
// 🔐 Staking
r.HandleFunc("/stake", h.StakeHandler).Methods("POST")
r.HandleFunc("/unstake", h.UnstakeHandler).Methods("POST")
r.HandleFunc("/stake/{address}", h.GetStakeInfo).Methods("GET")
// 🗳️ DAO
r.HandleFunc("/dao/proposals", h.CreateProposal).Methods("POST")
r.HandleFunc("/dao/proposals/{id}/vote", h.VoteProposal).Methods("POST")
r.HandleFunc("/dao/proposals", h.ListProposals).Methods("GET")
r.HandleFunc("/dao/proposals/{id}", h.GetProposal).Methods("GET")
// 💰 Accounts
r.HandleFunc("/accounts/{address}", HandleGetBalance).Methods("GET")
r.HandleFunc("/accounts/{address}/txs", HandleGetTransactionsByAddress).Methods("GET")
// 📦 Blocos
r.HandleFunc("/blocks", h.ListBlocks).Methods("GET") r.HandleFunc("/blocks", h.ListBlocks).Methods("GET")
r.HandleFunc("/blocks/{height}", h.GetBlockByHeight).Methods("GET") r.HandleFunc("/blocks/{height}", h.GetBlockByHeight).Methods("GET")
// ❤️ Heartbeat // Rotas de staking
r.HandleFunc("/ping", HandlePing).Methods("GET") r.HandleFunc("/stake", h.Stake).Methods("POST")
r.HandleFunc("/unstake", h.Unstake).Methods("POST")
r.HandleFunc("/stake-info", h.GetStakeInfo).Methods("GET")
return r // Rotas de transações
r.HandleFunc("/tx", h.SubmitTransaction).Methods("POST")
r.HandleFunc("/tx/{hash}", h.GetTransaction).Methods("GET")
// Rotas de consenso
r.HandleFunc("/consensus", h.HandleConsensus).Methods("POST")
// Health check
r.HandleFunc("/ping", h.Ping).Methods("GET")
} }

View File

@ -1,21 +1,19 @@
package api package api
import ( import (
"github.com/gorilla/mux"
"net/http"
"dejo_node/internal/ws" "dejo_node/internal/ws"
"net/http"
"github.com/gorilla/mux"
) )
func NewServer(handler *Handler) http.Handler { func NewServer(handler *Handler) http.Handler {
r := mux.NewRouter() r := mux.NewRouter()
// ⚠️ Endpoints removidos temporariamente pois ainda não foram implementados // Endpoints básicos
// r.HandleFunc("/block/latest", handler.GetLatestBlock).Methods("GET") r.HandleFunc("/ping", handler.Ping).Methods("GET")
// r.HandleFunc("/block/{index}", handler.GetBlockByIndex).Methods("GET") r.HandleFunc("/consensus", handler.HandleConsensus).Methods("POST")
// r.HandleFunc("/tx/{hash}", handler.GetTransactionByHash).Methods("GET")
// r.HandleFunc("/tx", handler.PostTransaction).Methods("POST")
// r.HandleFunc("/oracle/{key}", handler.GetOracleValue).Methods("GET")
r.HandleFunc("/ws", ws.HandleWS).Methods("GET") r.HandleFunc("/ws", ws.HandleWS).Methods("GET")
return r return r
} }

View File

@ -1,53 +1,52 @@
package api package api
import ( import (
"encoding/json"
"net/http" "net/http"
"github.com/gorilla/mux" "strconv"
) )
type StakeRequest struct {
Address string `json:"address"`
Amount uint64 `json:"amount"`
Duration int64 `json:"duration"`
}
type UnstakeRequest struct {
Address string `json:"address"`
}
func (h *Handler) StakeHandler(w http.ResponseWriter, r *http.Request) {
var req StakeRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
WriteError(w, http.StatusBadRequest, "Invalid request")
return
}
if err := h.StakingStore.Stake(req.Address, req.Amount, uint64(req.Duration)); err != nil {
WriteError(w, http.StatusInternalServerError, "Failed to stake")
return
}
WriteJSON(w, map[string]string{"message": "Stake registered successfully"})
}
func (h *Handler) UnstakeHandler(w http.ResponseWriter, r *http.Request) {
var req UnstakeRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
WriteError(w, http.StatusBadRequest, "Invalid request")
return
}
if err := h.StakingStore.Unstake(req.Address); err != nil {
WriteError(w, http.StatusInternalServerError, "Failed to unstake")
return
}
WriteJSON(w, map[string]string{"message": "Unstake successful"})
}
func (h *Handler) GetStakeInfo(w http.ResponseWriter, r *http.Request) { func (h *Handler) GetStakeInfo(w http.ResponseWriter, r *http.Request) {
address := mux.Vars(r)["address"] address := r.URL.Query().Get("address")
info, ok := h.StakingStore.GetStakeInfo(address) info, exists := h.StakingStore.GetStakeInfo(address)
if !ok { if !exists {
WriteError(w, http.StatusNotFound, "Stake info not found") WriteError(w, http.StatusNotFound, "Endereço não encontrado")
return return
} }
WriteJSON(w, info) WriteJSON(w, http.StatusOK, info)
}
func (h *Handler) Stake(w http.ResponseWriter, r *http.Request) {
address := r.URL.Query().Get("address")
amountStr := r.URL.Query().Get("amount")
durationStr := r.URL.Query().Get("duration")
amount, err := strconv.ParseUint(amountStr, 10, 64)
if err != nil {
WriteError(w, http.StatusBadRequest, "Valor inválido")
return
}
duration, err := strconv.ParseUint(durationStr, 10, 64)
if err != nil {
WriteError(w, http.StatusBadRequest, "Duração inválida")
return
}
err = h.StakingStore.Stake(address, amount, duration)
if err != nil {
WriteError(w, http.StatusInternalServerError, "Erro ao realizar stake")
return
}
w.WriteHeader(http.StatusOK)
}
func (h *Handler) Unstake(w http.ResponseWriter, r *http.Request) {
address := r.URL.Query().Get("address")
err := h.StakingStore.Unstake(address)
if err != nil {
WriteError(w, http.StatusInternalServerError, "Erro ao remover stake")
return
}
w.WriteHeader(http.StatusOK)
} }

View File

@ -1,30 +1,33 @@
package api package api
import ( import (
"encoding/json"
"log"
"net/http"
"dejo_node/internal/transactions" "dejo_node/internal/transactions"
"net/http"
) )
func (h *Handler) SendTransaction(w http.ResponseWriter, r *http.Request) { func (h *Handler) SubmitTransaction(w http.ResponseWriter, r *http.Request) {
log.Println("📥 Nova transação recebida")
var tx transactions.Transaction var tx transactions.Transaction
decoder := json.NewDecoder(r.Body) err := ReadJSON(r, &tx)
if err := decoder.Decode(&tx); err != nil { if err != nil {
http.Error(w, "formato inválido", http.StatusBadRequest) WriteError(w, http.StatusBadRequest, "Transação inválida")
return return
} }
if tx.From == "" || tx.To == "" || tx.Value <= 0 { err = h.Mempool.Add(&tx)
http.Error(w, "transação inválida", http.StatusBadRequest) if err != nil {
WriteError(w, http.StatusInternalServerError, "Erro ao adicionar transação")
return return
} }
h.Mempool.Add(&tx)
log.Printf("✅ Transação adicionada ao mempool: %+v\n", tx)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) }
func (h *Handler) GetTransaction(w http.ResponseWriter, r *http.Request) {
hash := r.URL.Query().Get("hash")
tx := h.Mempool.GetByHash(hash)
if tx == nil {
WriteError(w, http.StatusNotFound, "Transação não encontrada")
return
}
WriteJSON(w, http.StatusOK, tx)
} }

View File

@ -5,18 +5,17 @@ import (
"net/http" "net/http"
) )
func WriteError(w http.ResponseWriter, code int, msg string) { func WriteJSON(w http.ResponseWriter, status int, v any) error {
w.WriteHeader(code) w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{ w.WriteHeader(status)
"success": false, return json.NewEncoder(w).Encode(v)
"error": msg,
})
} }
func WriteJSON(w http.ResponseWriter, data interface{}) { func ReadJSON(r *http.Request, v any) error {
w.Header().Set("Content-Type", "application/json") return json.NewDecoder(r.Body).Decode(v)
_ = json.NewEncoder(w).Encode(map[string]interface{}{ }
"success": true,
"data": data, func WriteError(w http.ResponseWriter, status int, message string) {
}) w.WriteHeader(status)
json.NewEncoder(w).Encode(map[string]string{"error": message})
} }

View File

@ -16,8 +16,8 @@ const (
PhasePrevote = "PREVOTE" PhasePrevote = "PREVOTE"
PhasePrecommit = "PRECOMMIT" PhasePrecommit = "PRECOMMIT"
rewardAmount = 5 rewardAmount = 5
MaxRoundTimeout = 10 * time.Second MaxRoundTimeout = 10 * time.Second
) )
func StartConsensusLoop( func StartConsensusLoop(
@ -66,14 +66,13 @@ func StartConsensusLoop(
log.Println("🛑 Loop de consenso encerrado") log.Println("🛑 Loop de consenso encerrado")
return return
case <-ticker.C: case <-ticker.C:
roundState.Mu.Lock() currentRound := roundState.Round
if time.Since(roundState.LastRoundStart) > MaxRoundTimeout { if time.Since(roundState.LastRoundStart) > MaxRoundTimeout {
log.Println("⏰ Timeout! Reiniciando round", roundState.Round+1) log.Println("⏰ Timeout! Reiniciando round", currentRound+1)
roundState.ResetRound(roundState.Round + 1) roundState.ResetRound(currentRound + 1)
roundState.LastRoundStart = time.Now() roundState.LastRoundStart = time.Now()
phase = PhaseProposal phase = PhaseProposal
roundState.Mu.Unlock()
continue continue
} }
@ -95,7 +94,7 @@ func StartConsensusLoop(
BaseMsg: BaseMsg{ BaseMsg: BaseMsg{
MsgType: ProposalType, MsgType: ProposalType,
HeightVal: roundState.Height, HeightVal: roundState.Height,
RoundVal: roundState.Round, RoundVal: currentRound,
Validator: nodeID, Validator: nodeID,
Time: time.Now(), Time: time.Now(),
}, },
@ -107,15 +106,17 @@ func StartConsensusLoop(
case PhasePrevote: case PhasePrevote:
log.Println("🗳️ Fase de PREVOTE") log.Println("🗳️ Fase de PREVOTE")
proposalHash := roundState.Proposal
vote := PrevoteMsg{ vote := PrevoteMsg{
BaseMsg: BaseMsg{ BaseMsg: BaseMsg{
MsgType: PrevoteType, MsgType: PrevoteType,
HeightVal: roundState.Height, HeightVal: roundState.Height,
RoundVal: roundState.Round, RoundVal: currentRound,
Validator: nodeID, Validator: nodeID,
Time: time.Now(), Time: time.Now(),
}, },
BlockHash: roundState.Proposal, BlockHash: proposalHash,
} }
roundState.Prevotes[nodeID] = vote.BlockHash roundState.Prevotes[nodeID] = vote.BlockHash
broadcast(vote) broadcast(vote)
@ -123,15 +124,17 @@ func StartConsensusLoop(
case PhasePrecommit: case PhasePrecommit:
log.Println("🔐 Fase de PRECOMMIT") log.Println("🔐 Fase de PRECOMMIT")
proposalHash := roundState.Proposal
vote := PrecommitMsg{ vote := PrecommitMsg{
BaseMsg: BaseMsg{ BaseMsg: BaseMsg{
MsgType: PrecommitType, MsgType: PrecommitType,
HeightVal: roundState.Height, HeightVal: roundState.Height,
RoundVal: roundState.Round, RoundVal: currentRound,
Validator: nodeID, Validator: nodeID,
Time: time.Now(), Time: time.Now(),
}, },
BlockHash: roundState.Proposal, BlockHash: proposalHash,
} }
roundState.Precommits[nodeID] = vote.BlockHash roundState.Precommits[nodeID] = vote.BlockHash
broadcast(vote) broadcast(vote)
@ -164,11 +167,10 @@ func StartConsensusLoop(
} }
ApplySlash(roundState.Precommits, blockHash, stakingStore, validatorSet) ApplySlash(roundState.Precommits, blockHash, stakingStore, validatorSet)
} }
roundState.ResetRound(roundState.Round + 1) roundState.ResetRound(currentRound + 1)
roundState.LastRoundStart = time.Now() roundState.LastRoundStart = time.Now()
phase = PhaseProposal phase = PhaseProposal
} }
roundState.Mu.Unlock()
} }
} }
} }

View File

@ -1,39 +1,35 @@
package consensus package consensus
import ( import (
"sync"
"time" "time"
) )
// RoundState mantém o estado atual da altura e rodada de consenso. // RoundState mantém o estado atual da altura e rodada de consenso.
type RoundState struct { type RoundState struct {
Height uint64 // Altura atual do consenso (número do bloco) Height uint64 // Altura atual do consenso (número do bloco)
Round uint64 // Rodada atual (tentativas por altura) Round uint64 // Rodada atual (tentativas por altura)
LockedBlock string // Hash do bloco "travado" (caso tenha precommit anterior) LockedBlock string // Hash do bloco "travado" (caso tenha precommit anterior)
Proposal string // Hash da proposta atual recebida Proposal string // Hash da proposta atual recebida
Prevotes map[string]string // Mapa[ValidatorID] = BlockHash (pode ser vazio) Prevotes map[string]string // Mapa[ValidatorID] = BlockHash (pode ser vazio)
Precommits map[string]string // Mapa[ValidatorID] = BlockHash Precommits map[string]string // Mapa[ValidatorID] = BlockHash
LastRoundStart time.Time // 🆕 Controle de início da rodada LastRoundStart time.Time // Controle de início da rodada
Mu sync.RWMutex // Proteção de acesso concorrente
} }
// NewRoundState cria um estado novo para uma altura específica. // NewRoundState cria um estado novo para uma altura específica.
func NewRoundState(height uint64) *RoundState { func NewRoundState(height uint64) *RoundState {
return &RoundState{ return &RoundState{
Height: height, Height: height,
Round: 0, Round: 0,
LockedBlock: "", LockedBlock: "",
Proposal: "", Proposal: "",
Prevotes: make(map[string]string), Prevotes: make(map[string]string),
Precommits: make(map[string]string), Precommits: make(map[string]string),
LastRoundStart: time.Now(), LastRoundStart: time.Now(),
} }
} }
// ResetRound limpa os votos e proposta da rodada atual (usado ao iniciar nova rodada). // ResetRound limpa os votos e proposta da rodada atual (usado ao iniciar nova rodada).
func (rs *RoundState) ResetRound(round uint64) { func (rs *RoundState) ResetRound(round uint64) {
rs.Mu.Lock()
defer rs.Mu.Unlock()
rs.Round = round rs.Round = round
rs.Proposal = "" rs.Proposal = ""
rs.Prevotes = make(map[string]string) rs.Prevotes = make(map[string]string)

View File

@ -13,8 +13,9 @@ import (
) )
type HTTPTransport struct { type HTTPTransport struct {
peers []string peers []string
handlers map[MessageType]func(ConsensusMessage) handlers map[MessageType]func(ConsensusMessage)
receiveChan chan ConsensusMessage // Canal para enviar mensagens recebidas
} }
func NewHTTPTransport() *HTTPTransport { func NewHTTPTransport() *HTTPTransport {
@ -67,32 +68,43 @@ func (t *HTTPTransport) HandleIncoming(w http.ResponseWriter, r *http.Request) {
return return
} }
var msg ConsensusMessage
switch base.MsgType { switch base.MsgType {
case ProposalType: case ProposalType:
var msg ProposalMsg msg = &ProposalMsg{}
_ = json.Unmarshal(bodyBytes, &msg)
if h, ok := t.handlers[ProposalType]; ok {
h(msg)
}
case PrevoteType: case PrevoteType:
var msg PrevoteMsg msg = &PrevoteMsg{}
_ = json.Unmarshal(bodyBytes, &msg)
if h, ok := t.handlers[PrevoteType]; ok {
h(msg)
}
case PrecommitType: case PrecommitType:
var msg PrecommitMsg msg = &PrecommitMsg{}
_ = json.Unmarshal(bodyBytes, &msg)
if h, ok := t.handlers[PrecommitType]; ok {
h(msg)
}
default: default:
log.Println("⚠️ Tipo de mensagem desconhecido:", base.MsgType) log.Println("⚠️ Tipo de mensagem desconhecido:", base.MsgType)
w.WriteHeader(http.StatusBadRequest)
return
}
if err := json.Unmarshal(bodyBytes, msg); err != nil {
log.Println("❌ Erro ao decodificar mensagem:", err)
w.WriteHeader(http.StatusBadRequest)
return
}
select {
case t.receiveChan <- msg:
w.WriteHeader(http.StatusOK)
log.Printf("✅ Mensagem %s recebida de %s\n", base.MsgType, base.Validator)
default:
log.Println("⚠️ Canal de mensagens cheio - descartando mensagem")
w.WriteHeader(http.StatusServiceUnavailable)
} }
w.WriteHeader(http.StatusOK)
} }
// PingPeer envia um ping para o peer e espera resposta. // PingPeer envia um ping para o peer e espera resposta.
func (t *HTTPTransport) Receive() <-chan ConsensusMessage {
ch := make(chan ConsensusMessage, 100)
t.receiveChan = ch // Armazena o canal para uso nos handlers
return ch
}
func (t *HTTPTransport) PingPeer(peer string) error { func (t *HTTPTransport) PingPeer(peer string) error {
client := http.Client{ client := http.Client{
Timeout: 2 * time.Second, Timeout: 2 * time.Second,

View File

@ -23,3 +23,7 @@ func (m *Mempool) All() []*transactions.Transaction {
func (m *Mempool) Clear() { func (m *Mempool) Clear() {
m.transactions = []*transactions.Transaction{} m.transactions = []*transactions.Transaction{}
} }
func (m *Mempool) GetTransactions() []*transactions.Transaction {
return m.transactions
}

BIN
main

Binary file not shown.