diff --git a/.env b/.env new file mode 100755 index 0000000..cf53ca5 --- /dev/null +++ b/.env @@ -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 \ No newline at end of file diff --git a/changelog.md b/changelog.md index fbbb010..45bb2f0 100644 --- a/changelog.md +++ b/changelog.md @@ -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 -- Organização de diretórios `cmd/`, `internal/`, `pkg/` -- Dockerfile, Makefile e configs prontos -- `main.go` funcional +### Features -### 🔐 Transações -- Estrutura básica de TX (`from`, `to`, `value`, `nonce`, `signature`) -- Validações e verificação de assinatura -- Mempool integrada +* teste deploy Upgrade karpenter k8s v.027 para 1.20 ([bff2c0a](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/bff2c0abff5908cd03240c33ef0a6eb4b64b79ff)) -### 📦 Armazenamento -- Implementação com LevelDB -- Indexação por hash e blocos +# [1.5.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.4.0...v1.5.0) (2025-06-12) -### 🌐 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 -- Algoritmo mínimo viável tipo PoA/BFT -- Validação e finalização de blocos +### Features -### 🔗 API REST -- Endpoints: `/tx`, `/tx/{hash}`, `/block/{hash}`, `/mempool` -- Health checks: `/health`, `/startup`, `/ready` +* Alteração trigger deploy branch master para dev ([dbe89a5](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/dbe89a5cc4132c867a09827a005436bc538933fd)) +* Alteração trigger deploy branch master para dev ([0ec68b0](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/0ec68b07bc208c59ad5d431cfc89b561cc82991e)) +* 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 -- Estrutura de staking e votação -- RPCs para propostas e eleição +# [1.3.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.2.0...v1.3.0) (2025-06-11) -### 🛰️ Oráculos -- Placeholder e endpoint para feed externo validado -### 🔐 Segurança -- Rate Limiting anti-DDoS -- Monitoramento de conexões suspeitas -- Modularização para reputação de peer +### Features -### 📊 DevOps -- `/metrics` com Prometheus (`tx_total`, `uptime`) -- `openapi.yaml` com documentação completa +* Alteração trigger deploy branch master para dev ([13b7ccb](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/13b7ccb1bf718b16dcad3dd81fe4e8cb9dd2a31c)) ---- +# [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)) diff --git a/cmd/main.go b/cmd/main.go index 8b08672..ff15d78 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -4,13 +4,11 @@ import ( "context" "dejo_node/internal/api" "dejo_node/internal/consensus" - "dejo_node/internal/mempool" - "dejo_node/internal/monitor" "dejo_node/internal/staking" - "dejo_node/internal/state" "dejo_node/internal/storage" "dejo_node/internal/transactions" "fmt" + "log" "net/http" "os" "strings" @@ -22,33 +20,52 @@ func main() { nodeID := os.Getenv("NODE_ID") 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() - mp := mempool.NewMempool() - globalState := state.NewState() - // Heartbeat function - pingPeer := func(peer string) bool { - client := http.Client{Timeout: 2 * time.Second} - resp, err := client.Get(peer + "/health") - if err != nil { - return false - } - defer resp.Body.Close() - return resp.StatusCode == http.StatusOK + // Carregar staking existente se disponível + if err := stakingStore.LoadFromDisk("./data/staking.db"); err != nil { + fmt.Println("ℹ️ Criando novo staking store") } - 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) go func() { - fmt.Printf("🌐 Servidor HTTP iniciado na porta :%s\n", port) - http.ListenAndServe(":"+port, server) + addr := ":" + port + 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) @@ -58,16 +75,16 @@ func main() { ctx, nodeID, round, - transport.Receive, + transport.Broadcast, 700, blockStore, func() *transactions.Block { return &transactions.Block{ - Txns: mp.GetTransactions(), + Txns: mp.All(), } }, stakingStore, - globalState, - monitor, + 1000, // minStake + &consensus.LivenessMonitor{}, ) } diff --git a/data/blocks/block_005.json b/data/blocks/block_005.json new file mode 100644 index 0000000..37cb808 --- /dev/null +++ b/data/blocks/block_005.json @@ -0,0 +1,8 @@ +{ + "Index": 5, + "PrevHash": "4519522e80850a467c571eccdbad3a9b078b75d0dd3c889a87725c207eff3464", + "Txns": [], + "Timestamp": 1750195439, + "Nonce": 0, + "Hash": "ca8e1c74e4bbfbdd7e820f1f86f36f25fdac819253b85d86a0321ec2c52f8776" +} \ No newline at end of file diff --git a/data/blocks/block_006.json b/data/blocks/block_006.json new file mode 100644 index 0000000..f622e9d --- /dev/null +++ b/data/blocks/block_006.json @@ -0,0 +1,8 @@ +{ + "Index": 6, + "PrevHash": "ca8e1c74e4bbfbdd7e820f1f86f36f25fdac819253b85d86a0321ec2c52f8776", + "Txns": [], + "Timestamp": 1750195445, + "Nonce": 0, + "Hash": "32592e38f35ee21d71452ffe62ab7a834f3d284fb06d9d114ed7d6f03aee1ebc" +} \ No newline at end of file diff --git a/data/blocks/block_007.json b/data/blocks/block_007.json new file mode 100644 index 0000000..b7f51d1 --- /dev/null +++ b/data/blocks/block_007.json @@ -0,0 +1,8 @@ +{ + "Index": 7, + "PrevHash": "32592e38f35ee21d71452ffe62ab7a834f3d284fb06d9d114ed7d6f03aee1ebc", + "Txns": [], + "Timestamp": 1750195489, + "Nonce": 0, + "Hash": "a2b5387b1956fe5f310040ff6a80724b6e5f62e9d6b8d813397f1f14cbda5a24" +} \ No newline at end of file diff --git a/data/blocks/block_008.json b/data/blocks/block_008.json new file mode 100644 index 0000000..6ef2424 --- /dev/null +++ b/data/blocks/block_008.json @@ -0,0 +1,8 @@ +{ + "Index": 8, + "PrevHash": "a2b5387b1956fe5f310040ff6a80724b6e5f62e9d6b8d813397f1f14cbda5a24", + "Txns": [], + "Timestamp": 1750195495, + "Nonce": 0, + "Hash": "90bc5fa197ba90c74e5bd078dd26e9cb00be40d4d01daf254dc9f8a40b3cbd48" +} \ No newline at end of file diff --git a/data/blocks/block_009.json b/data/blocks/block_009.json new file mode 100644 index 0000000..5a05644 --- /dev/null +++ b/data/blocks/block_009.json @@ -0,0 +1,8 @@ +{ + "Index": 9, + "PrevHash": "90bc5fa197ba90c74e5bd078dd26e9cb00be40d4d01daf254dc9f8a40b3cbd48", + "Txns": [], + "Timestamp": 1750195501, + "Nonce": 0, + "Hash": "93c559f77585fb86e6729f2d079fb735b102fdb38973d02c73d4f4efd77f3316" +} \ No newline at end of file diff --git a/data/blocks/block_010.json b/data/blocks/block_010.json new file mode 100644 index 0000000..5e52b6e --- /dev/null +++ b/data/blocks/block_010.json @@ -0,0 +1,8 @@ +{ + "Index": 10, + "PrevHash": "93c559f77585fb86e6729f2d079fb735b102fdb38973d02c73d4f4efd77f3316", + "Txns": [], + "Timestamp": 1750195507, + "Nonce": 0, + "Hash": "0bf32341956d3c155fa2bdd454561c3859baea5c8a13239855b12ceb8bc874c9" +} \ No newline at end of file diff --git a/data/blocks/block_011.json b/data/blocks/block_011.json new file mode 100644 index 0000000..aa3a8e9 --- /dev/null +++ b/data/blocks/block_011.json @@ -0,0 +1,8 @@ +{ + "Index": 11, + "PrevHash": "0bf32341956d3c155fa2bdd454561c3859baea5c8a13239855b12ceb8bc874c9", + "Txns": [], + "Timestamp": 1750195513, + "Nonce": 0, + "Hash": "b92362e0300cbc2d09c1dab53124ca4821ef3baf2c399690765fc989cc33c23c" +} \ No newline at end of file diff --git a/data/blocks/block_012.json b/data/blocks/block_012.json new file mode 100644 index 0000000..a795722 --- /dev/null +++ b/data/blocks/block_012.json @@ -0,0 +1,8 @@ +{ + "Index": 12, + "PrevHash": "b92362e0300cbc2d09c1dab53124ca4821ef3baf2c399690765fc989cc33c23c", + "Txns": [], + "Timestamp": 1750195519, + "Nonce": 0, + "Hash": "04027d627f5ae9acc0924fe38a7a5e0cd8b1dac11e0d71adee5e8814e2b99dd6" +} \ No newline at end of file diff --git a/data/blocks/block_013.json b/data/blocks/block_013.json new file mode 100644 index 0000000..0696203 --- /dev/null +++ b/data/blocks/block_013.json @@ -0,0 +1,8 @@ +{ + "Index": 13, + "PrevHash": "04027d627f5ae9acc0924fe38a7a5e0cd8b1dac11e0d71adee5e8814e2b99dd6", + "Txns": [], + "Timestamp": 1750195525, + "Nonce": 0, + "Hash": "bd45896e0e62abb6be4116011cfa322d51b8185730e0b02c58ef3a50adc2fdae" +} \ No newline at end of file diff --git a/data/blocks/block_014.json b/data/blocks/block_014.json new file mode 100644 index 0000000..85628b8 --- /dev/null +++ b/data/blocks/block_014.json @@ -0,0 +1,8 @@ +{ + "Index": 14, + "PrevHash": "bd45896e0e62abb6be4116011cfa322d51b8185730e0b02c58ef3a50adc2fdae", + "Txns": [], + "Timestamp": 1750195531, + "Nonce": 0, + "Hash": "605c17882f09e6a1065cd2599ff14d4440f98f6a2a9143e2ac3f519f6dd8b605" +} \ No newline at end of file diff --git a/data/staking.db b/data/staking.db index 2ec7ad1..73d7891 100644 Binary files a/data/staking.db and b/data/staking.db differ diff --git a/data/state.gob b/data/state.gob index 6f4cb9f..6653c7c 100644 Binary files a/data/state.gob and b/data/state.gob differ diff --git a/go.mod b/go.mod index f5f976a..6cb8152 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,6 @@ require ( github.com/libp2p/go-libp2p-kad-dht v0.30.2 github.com/multiformats/go-multiaddr v0.15.0 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 go.uber.org/zap v1.27.0 ) @@ -23,7 +21,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/cgroups v1.1.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/decred/dcrd/dcrec/secp256k1/v4 v4.4.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/godbus/dbus/v5 v5.1.0 // 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/pprof v0.0.0-20250208200701-d0013a598941 // 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/webrtc/v4 v4.0.10 // 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/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect @@ -134,6 +129,5 @@ require ( golang.org/x/tools v0.30.0 // indirect gonum.org/v1/gonum v0.15.1 // indirect google.golang.org/protobuf v1.36.5 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index ac83700..60b618b 100644 --- a/go.sum +++ b/go.sum @@ -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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= 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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 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/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/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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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/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/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/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= 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/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/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/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/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 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/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= 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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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/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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/api/block_handlers.go b/internal/api/block_handlers.go index f9085d8..437326d 100644 --- a/internal/api/block_handlers.go +++ b/internal/api/block_handlers.go @@ -3,6 +3,7 @@ package api import ( "net/http" "strconv" + "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") return } - WriteJSON(w, blocks) + WriteJSON(w, http.StatusOK, blocks) } 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") return } - WriteJSON(w, block) -} \ No newline at end of file + WriteJSON(w, http.StatusOK, block) +} diff --git a/internal/api/dao_handlers.go b/internal/api/dao_handlers.go index d895bdd..5d2f2d0 100644 --- a/internal/api/dao_handlers.go +++ b/internal/api/dao_handlers.go @@ -5,8 +5,9 @@ import ( "net/http" "strconv" - "github.com/gorilla/mux" "dejo_node/internal/dao" + + "github.com/gorilla/mux" ) 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) _ = DaoStore.SaveToDisk("data/proposals.db") - WriteJSON(w, p) + WriteJSON(w, http.StatusOK, p) } 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.CheckAndClose(h.snapshotStakes()) _ = DaoStore.SaveToDisk("data/proposals.db") - WriteJSON(w, p) + WriteJSON(w, http.StatusOK, p) } 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") return } - WriteJSON(w, p) + WriteJSON(w, http.StatusOK, p) } 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 { @@ -81,4 +82,4 @@ func (h *Handler) snapshotStakes() map[string]uint64 { snapshot[addr] = entry.Amount } return snapshot -} \ No newline at end of file +} diff --git a/internal/api/handler.go b/internal/api/handler.go index bb03716..269b150 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -1,20 +1,33 @@ package api import ( - "dejo_node/internal/mempool" "dejo_node/internal/staking" "dejo_node/internal/storage" + "dejo_node/internal/transactions" + "net/http" ) type Handler struct { Store *storage.BlockStore StakingStore *staking.StakingStore - Mempool *mempool.Mempool + Mempool *transactions.Mempool } func NewHandler() *Handler { - return &Handler{ - Store: storage.NewBlockStore("data/blocks.json"), - StakingStore: staking.NewStakingStore(), - } -} \ No newline at end of file + return &Handler{} +} + +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) +} diff --git a/internal/api/health.go b/internal/api/health.go index b00d846..fca9a7d 100644 --- a/internal/api/health.go +++ b/internal/api/health.go @@ -2,9 +2,10 @@ package api import ( "net/http" + "time" ) func (h *Handler) Health(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte("ok")) -} \ No newline at end of file + w.Write([]byte(time.Now().Format(time.RFC3339))) +} diff --git a/internal/api/router.go b/internal/api/router.go index ff06b33..87f8463 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -2,41 +2,25 @@ package api import ( "github.com/gorilla/mux" - "net/http" ) -func NewRouter(h *Handler) http.Handler { - r := mux.NewRouter() - - 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 +func (h *Handler) RegisterRoutes(r *mux.Router) { + // Rotas de blocos r.HandleFunc("/blocks", h.ListBlocks).Methods("GET") r.HandleFunc("/blocks/{height}", h.GetBlockByHeight).Methods("GET") - // ❤️ Heartbeat - r.HandleFunc("/ping", HandlePing).Methods("GET") + // Rotas de staking + r.HandleFunc("/stake", h.Stake).Methods("POST") + r.HandleFunc("/unstake", h.Unstake).Methods("POST") + r.HandleFunc("/stake-info", h.GetStakeInfo).Methods("GET") - return r -} \ No newline at end of file + // 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") +} diff --git a/internal/api/server.go b/internal/api/server.go index 09a87e1..aeb2198 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -1,21 +1,19 @@ package api import ( - "github.com/gorilla/mux" - "net/http" "dejo_node/internal/ws" + "net/http" + + "github.com/gorilla/mux" ) func NewServer(handler *Handler) http.Handler { r := mux.NewRouter() - // ⚠️ Endpoints removidos temporariamente pois ainda não foram implementados - // r.HandleFunc("/block/latest", handler.GetLatestBlock).Methods("GET") - // r.HandleFunc("/block/{index}", handler.GetBlockByIndex).Methods("GET") - // r.HandleFunc("/tx/{hash}", handler.GetTransactionByHash).Methods("GET") - // r.HandleFunc("/tx", handler.PostTransaction).Methods("POST") - // r.HandleFunc("/oracle/{key}", handler.GetOracleValue).Methods("GET") - + // Endpoints básicos + r.HandleFunc("/ping", handler.Ping).Methods("GET") + r.HandleFunc("/consensus", handler.HandleConsensus).Methods("POST") r.HandleFunc("/ws", ws.HandleWS).Methods("GET") + return r -} \ No newline at end of file +} diff --git a/internal/api/staking_handlers.go b/internal/api/staking_handlers.go index 0063e62..e609db8 100644 --- a/internal/api/staking_handlers.go +++ b/internal/api/staking_handlers.go @@ -1,53 +1,52 @@ package api import ( - "encoding/json" "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) { - address := mux.Vars(r)["address"] - info, ok := h.StakingStore.GetStakeInfo(address) - if !ok { - WriteError(w, http.StatusNotFound, "Stake info not found") + address := r.URL.Query().Get("address") + info, exists := h.StakingStore.GetStakeInfo(address) + if !exists { + WriteError(w, http.StatusNotFound, "Endereço não encontrado") return } - WriteJSON(w, info) -} \ No newline at end of file + 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) +} diff --git a/internal/api/tx_handlers.go b/internal/api/tx_handlers.go index 9bb08a4..5fdbdbb 100644 --- a/internal/api/tx_handlers.go +++ b/internal/api/tx_handlers.go @@ -1,30 +1,33 @@ package api import ( - "encoding/json" - "log" - "net/http" "dejo_node/internal/transactions" + "net/http" ) -func (h *Handler) SendTransaction(w http.ResponseWriter, r *http.Request) { - log.Println("📥 Nova transação recebida") +func (h *Handler) SubmitTransaction(w http.ResponseWriter, r *http.Request) { var tx transactions.Transaction - decoder := json.NewDecoder(r.Body) - if err := decoder.Decode(&tx); err != nil { - http.Error(w, "formato inválido", http.StatusBadRequest) + err := ReadJSON(r, &tx) + if err != nil { + WriteError(w, http.StatusBadRequest, "Transação inválida") return } - if tx.From == "" || tx.To == "" || tx.Value <= 0 { - http.Error(w, "transação inválida", http.StatusBadRequest) + err = h.Mempool.Add(&tx) + if err != nil { + WriteError(w, http.StatusInternalServerError, "Erro ao adicionar transação") 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) - json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) -} \ No newline at end of file +} + +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) +} diff --git a/internal/api/utils.go b/internal/api/utils.go index d1793e0..49558cf 100644 --- a/internal/api/utils.go +++ b/internal/api/utils.go @@ -5,18 +5,17 @@ import ( "net/http" ) -func WriteError(w http.ResponseWriter, code int, msg string) { - w.WriteHeader(code) - _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "success": false, - "error": msg, - }) +func WriteJSON(w http.ResponseWriter, status int, v any) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + return json.NewEncoder(w).Encode(v) } -func WriteJSON(w http.ResponseWriter, data interface{}) { - w.Header().Set("Content-Type", "application/json") - _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "success": true, - "data": data, - }) -} \ No newline at end of file +func ReadJSON(r *http.Request, v any) error { + return json.NewDecoder(r.Body).Decode(v) +} + +func WriteError(w http.ResponseWriter, status int, message string) { + w.WriteHeader(status) + json.NewEncoder(w).Encode(map[string]string{"error": message}) +} diff --git a/internal/consensus/round_loop.go b/internal/consensus/round_loop.go index 1412d0d..557f7ad 100644 --- a/internal/consensus/round_loop.go +++ b/internal/consensus/round_loop.go @@ -16,8 +16,8 @@ const ( PhasePrevote = "PREVOTE" PhasePrecommit = "PRECOMMIT" - rewardAmount = 5 - MaxRoundTimeout = 10 * time.Second + rewardAmount = 5 + MaxRoundTimeout = 10 * time.Second ) func StartConsensusLoop( @@ -66,14 +66,13 @@ func StartConsensusLoop( log.Println("🛑 Loop de consenso encerrado") return case <-ticker.C: - roundState.Mu.Lock() + currentRound := roundState.Round if time.Since(roundState.LastRoundStart) > MaxRoundTimeout { - log.Println("⏰ Timeout! Reiniciando round", roundState.Round+1) - roundState.ResetRound(roundState.Round + 1) + log.Println("⏰ Timeout! Reiniciando round", currentRound+1) + roundState.ResetRound(currentRound + 1) roundState.LastRoundStart = time.Now() phase = PhaseProposal - roundState.Mu.Unlock() continue } @@ -95,7 +94,7 @@ func StartConsensusLoop( BaseMsg: BaseMsg{ MsgType: ProposalType, HeightVal: roundState.Height, - RoundVal: roundState.Round, + RoundVal: currentRound, Validator: nodeID, Time: time.Now(), }, @@ -107,15 +106,17 @@ func StartConsensusLoop( case PhasePrevote: log.Println("🗳️ Fase de PREVOTE") + proposalHash := roundState.Proposal + vote := PrevoteMsg{ BaseMsg: BaseMsg{ MsgType: PrevoteType, HeightVal: roundState.Height, - RoundVal: roundState.Round, + RoundVal: currentRound, Validator: nodeID, Time: time.Now(), }, - BlockHash: roundState.Proposal, + BlockHash: proposalHash, } roundState.Prevotes[nodeID] = vote.BlockHash broadcast(vote) @@ -123,15 +124,17 @@ func StartConsensusLoop( case PhasePrecommit: log.Println("🔐 Fase de PRECOMMIT") + proposalHash := roundState.Proposal + vote := PrecommitMsg{ BaseMsg: BaseMsg{ MsgType: PrecommitType, HeightVal: roundState.Height, - RoundVal: roundState.Round, + RoundVal: currentRound, Validator: nodeID, Time: time.Now(), }, - BlockHash: roundState.Proposal, + BlockHash: proposalHash, } roundState.Precommits[nodeID] = vote.BlockHash broadcast(vote) @@ -164,11 +167,10 @@ func StartConsensusLoop( } ApplySlash(roundState.Precommits, blockHash, stakingStore, validatorSet) } - roundState.ResetRound(roundState.Round + 1) + roundState.ResetRound(currentRound + 1) roundState.LastRoundStart = time.Now() phase = PhaseProposal } - roundState.Mu.Unlock() } } -} \ No newline at end of file +} diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 3452c4d..5df908a 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1,42 +1,38 @@ package consensus import ( - "sync" "time" ) // RoundState mantém o estado atual da altura e rodada de consenso. type RoundState struct { - Height uint64 // Altura atual do consenso (número do bloco) - Round uint64 // Rodada atual (tentativas por altura) - LockedBlock string // Hash do bloco "travado" (caso tenha precommit anterior) - Proposal string // Hash da proposta atual recebida - Prevotes map[string]string // Mapa[ValidatorID] = BlockHash (pode ser vazio) - Precommits map[string]string // Mapa[ValidatorID] = BlockHash - LastRoundStart time.Time // 🆕 Controle de início da rodada - Mu sync.RWMutex // Proteção de acesso concorrente + Height uint64 // Altura atual do consenso (número do bloco) + Round uint64 // Rodada atual (tentativas por altura) + LockedBlock string // Hash do bloco "travado" (caso tenha precommit anterior) + Proposal string // Hash da proposta atual recebida + Prevotes map[string]string // Mapa[ValidatorID] = BlockHash (pode ser vazio) + Precommits map[string]string // Mapa[ValidatorID] = BlockHash + LastRoundStart time.Time // Controle de início da rodada } // NewRoundState cria um estado novo para uma altura específica. func NewRoundState(height uint64) *RoundState { return &RoundState{ - Height: height, - Round: 0, - LockedBlock: "", - Proposal: "", - Prevotes: make(map[string]string), - Precommits: make(map[string]string), - LastRoundStart: time.Now(), + Height: height, + Round: 0, + LockedBlock: "", + Proposal: "", + Prevotes: make(map[string]string), + Precommits: make(map[string]string), + LastRoundStart: time.Now(), } } // ResetRound limpa os votos e proposta da rodada atual (usado ao iniciar nova rodada). func (rs *RoundState) ResetRound(round uint64) { - rs.Mu.Lock() - defer rs.Mu.Unlock() rs.Round = round rs.Proposal = "" rs.Prevotes = make(map[string]string) rs.Precommits = make(map[string]string) rs.LastRoundStart = time.Now() -} \ No newline at end of file +} diff --git a/internal/consensus/transport_http.go b/internal/consensus/transport_http.go index c58c5bf..7440a66 100644 --- a/internal/consensus/transport_http.go +++ b/internal/consensus/transport_http.go @@ -13,8 +13,9 @@ import ( ) type HTTPTransport struct { - peers []string - handlers map[MessageType]func(ConsensusMessage) + peers []string + handlers map[MessageType]func(ConsensusMessage) + receiveChan chan ConsensusMessage // Canal para enviar mensagens recebidas } func NewHTTPTransport() *HTTPTransport { @@ -67,32 +68,43 @@ func (t *HTTPTransport) HandleIncoming(w http.ResponseWriter, r *http.Request) { return } + var msg ConsensusMessage switch base.MsgType { case ProposalType: - var msg ProposalMsg - _ = json.Unmarshal(bodyBytes, &msg) - if h, ok := t.handlers[ProposalType]; ok { - h(msg) - } + msg = &ProposalMsg{} case PrevoteType: - var msg PrevoteMsg - _ = json.Unmarshal(bodyBytes, &msg) - if h, ok := t.handlers[PrevoteType]; ok { - h(msg) - } + msg = &PrevoteMsg{} case PrecommitType: - var msg PrecommitMsg - _ = json.Unmarshal(bodyBytes, &msg) - if h, ok := t.handlers[PrecommitType]; ok { - h(msg) - } + msg = &PrecommitMsg{} default: 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. +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 { client := http.Client{ Timeout: 2 * time.Second, @@ -106,4 +118,4 @@ func (t *HTTPTransport) PingPeer(peer string) error { return errors.New("resposta inválida ao ping") } return nil -} \ No newline at end of file +} diff --git a/internal/mempool/mempool.go b/internal/mempool/mempool.go index 76ba7e2..89cda62 100644 --- a/internal/mempool/mempool.go +++ b/internal/mempool/mempool.go @@ -23,3 +23,7 @@ func (m *Mempool) All() []*transactions.Transaction { func (m *Mempool) Clear() { m.transactions = []*transactions.Transaction{} } + +func (m *Mempool) GetTransactions() []*transactions.Transaction { + return m.transactions +} diff --git a/main b/main index 1dc9490..0b98447 100755 Binary files a/main and b/main differ