Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9265171a5e | |||
| 9259f36e9c | |||
| 682027d517 | |||
| 7419f66c83 | |||
| ad2ee20cb4 | |||
| bff2c0abff | |||
| 2012ff2d81 | |||
| f9fca8c0a0 | |||
| 782ad9aadc | |||
| bb116a2780 | |||
| 086d68bfaf | |||
| dbe89a5cc4 | |||
| 80c1a5a9b7 | |||
| 0ec68b07bc | |||
| 2237d84ad2 | |||
| 8208b46622 | |||
| b22e210578 | |||
| 70d8fe4906 | |||
| b0d9105ceb | |||
| 771281d8af | |||
| c6dbbd3fd4 | |||
| c1c1232c87 | |||
| 3a4c96f0dc | |||
| 13b7ccb1bf | |||
| 82af370358 | |||
| 84a35b08a1 | |||
| 175b94b680 | |||
| 6363e7a9d5 | |||
| 043ab1fdfc | |||
| 15bb0872f8 | |||
| 1b2aaff753 | |||
| 772a1ac9e9 |
5
.env
Executable file
5
.env
Executable 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
|
||||||
@ -4,8 +4,7 @@ name: CI & CD
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- dev
|
||||||
#- dev
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint_commits:
|
lint_commits:
|
||||||
@ -24,12 +23,11 @@ jobs:
|
|||||||
run: npm ci --no-audit
|
run: npm ci --no-audit
|
||||||
|
|
||||||
- name: Lint Commit Messages
|
- name: Lint Commit Messages
|
||||||
# Se qualquer mensagem não corresponder ao Conventional Commits, este step falha
|
run: npx commitlint --from=origin/dev --to=HEAD
|
||||||
run: npx commitlint --from=origin/master --to=HEAD
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
needs: lint_commits # só roda se lint_commits passar
|
needs: lint_commits
|
||||||
runs-on: [self-hosted]
|
runs-on: [self-hosted]
|
||||||
outputs:
|
outputs:
|
||||||
sha_short: ${{ steps.commit_short.outputs.sha_short }}
|
sha_short: ${{ steps.commit_short.outputs.sha_short }}
|
||||||
@ -71,12 +69,12 @@ jobs:
|
|||||||
build_and_push:
|
build_and_push:
|
||||||
name: Docker | Build and Push
|
name: Docker | Build and Push
|
||||||
needs: release
|
needs: release
|
||||||
if: ${{ needs.release.outputs.is_tagged == 'true' }} # só roda se semantic-release criou tag
|
if: ${{ needs.release.outputs.is_tagged == 'true' }}
|
||||||
runs-on: [self-hosted]
|
runs-on: [self-hosted]
|
||||||
env:
|
env:
|
||||||
DEJO_NODE_AWS_REGION: us-east-1
|
DEJO_NODE_AWS_REGION: us-east-1
|
||||||
AWS_ECR_REPOSITORY: dev-dejo/dejo-node
|
AWS_ECR_REPOSITORY: dev-dejo/dejo-node
|
||||||
DISABLE_DISCORD_NOTIFY: true
|
DISABLE_DISCORD_NOTIFY: false
|
||||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
sha_short: ${{ needs.release.outputs.sha_short }}
|
sha_short: ${{ needs.release.outputs.sha_short }}
|
||||||
steps:
|
steps:
|
||||||
@ -114,10 +112,12 @@ jobs:
|
|||||||
password: ${{ secrets.DEJO_NODE_AWS_SECRET_KEY }}
|
password: ${{ secrets.DEJO_NODE_AWS_SECRET_KEY }}
|
||||||
|
|
||||||
- name: Build and Push Backend
|
- name: Build and Push Backend
|
||||||
|
id: build_push
|
||||||
|
continue-on-error: true
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: infrastructure
|
context: .
|
||||||
file: infrastructure/Dockerfile
|
file: ./Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
${{ secrets.DEV_DEJO_AWS_ECR_REGISTRY }}/${{ env.AWS_ECR_REPOSITORY }}:latest
|
${{ secrets.DEV_DEJO_AWS_ECR_REGISTRY }}/${{ env.AWS_ECR_REPOSITORY }}:latest
|
||||||
@ -125,11 +125,29 @@ jobs:
|
|||||||
cache-from: type=local,src=/tmp/.buildx-cache
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new
|
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new
|
||||||
|
|
||||||
|
- name: Discord | Notify Error (Build)
|
||||||
|
if: steps.build_push.outcome == 'failure' && env.DISABLE_DISCORD_NOTIFY != 'true'
|
||||||
|
run: |
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"content":":x: Falha no build/push do Docker. Veja logs."}' \
|
||||||
|
"${DISCORD_WEBHOOK}"
|
||||||
|
|
||||||
|
- name: Fail job if build_push failed
|
||||||
|
if: steps.build_push.outcome == 'failure'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
- name: Moving Cache
|
- name: Moving Cache
|
||||||
run: |
|
run: |
|
||||||
rm -rf /tmp/.buildx-cache
|
rm -rf /tmp/.buildx-cache
|
||||||
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||||
|
|
||||||
|
- name: Discord | Notify Success (Build)
|
||||||
|
if: steps.build_push.outcome == 'success' && env.DISABLE_DISCORD_NOTIFY != 'true'
|
||||||
|
run: |
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"content":":white_check_mark: Build e push do Docker concluídos com sucesso."}' \
|
||||||
|
"${DISCORD_WEBHOOK}"
|
||||||
|
|
||||||
kustomize_apply:
|
kustomize_apply:
|
||||||
name: Kubernetes | Kustomize Apply
|
name: Kubernetes | Kustomize Apply
|
||||||
needs: build_and_push
|
needs: build_and_push
|
||||||
@ -137,6 +155,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DEJO_NODE_AWS_REGION: us-east-1
|
DEJO_NODE_AWS_REGION: us-east-1
|
||||||
KUBE_NAMESPACE: dejo-node
|
KUBE_NAMESPACE: dejo-node
|
||||||
|
DISABLE_DISCORD_NOTIFY: false
|
||||||
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@ -151,11 +171,31 @@ jobs:
|
|||||||
aws-region: ${{ env.DEJO_NODE_AWS_REGION }}
|
aws-region: ${{ env.DEJO_NODE_AWS_REGION }}
|
||||||
|
|
||||||
- name: Apply Kustomize
|
- name: Apply Kustomize
|
||||||
|
id: kustomize
|
||||||
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.DEJO_NODE_KUBE_CONFIG_DATA_DEV }}" | base64 -d > kubeconfig
|
echo "${{ secrets.DEJO_NODE_KUBE_CONFIG_DATA_DEV }}" | base64 -d > kubeconfig
|
||||||
export KUBECONFIG=$PWD/kubeconfig
|
export KUBECONFIG=$PWD/kubeconfig
|
||||||
kubectl apply -k infrastructure/kubernetes/dev -n "${KUBE_NAMESPACE}"
|
kubectl apply -k infrastructure/kubernetes/dev -n "${KUBE_NAMESPACE}"
|
||||||
|
|
||||||
|
- name: Discord | Notify Error (Kustomize)
|
||||||
|
if: steps.kustomize.outcome == 'failure' && env.DISABLE_DISCORD_NOTIFY != 'true'
|
||||||
|
run: |
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"content":":x: Falha ao aplicar Kustomize. Veja logs."}' \
|
||||||
|
"${DISCORD_WEBHOOK}"
|
||||||
|
|
||||||
|
- name: Fail job if kustomize failed
|
||||||
|
if: steps.kustomize.outcome == 'failure'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- name: Discord | Notify Success (Kustomize)
|
||||||
|
if: steps.kustomize.outcome == 'success' && env.DISABLE_DISCORD_NOTIFY != 'true'
|
||||||
|
run: |
|
||||||
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
|
-d '{"content":":white_check_mark: Kustomize aplicado com sucesso."}' \
|
||||||
|
"${DISCORD_WEBHOOK}"
|
||||||
|
|
||||||
deploy_backend:
|
deploy_backend:
|
||||||
name: Kubernetes | Deploy App
|
name: Kubernetes | Deploy App
|
||||||
needs: kustomize_apply
|
needs: kustomize_apply
|
||||||
@ -165,7 +205,7 @@ jobs:
|
|||||||
AWS_ECR_REPOSITORY: dev-dejo/dejo-node
|
AWS_ECR_REPOSITORY: dev-dejo/dejo-node
|
||||||
KUBE_NAMESPACE: dejo-node
|
KUBE_NAMESPACE: dejo-node
|
||||||
KUBE_DEPLOY_NAME: api-app
|
KUBE_DEPLOY_NAME: api-app
|
||||||
DISABLE_DISCORD_NOTIFY: true
|
DISABLE_DISCORD_NOTIFY: false
|
||||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||||
sha_short: ${{ needs.release.outputs.sha_short }}
|
sha_short: ${{ needs.release.outputs.sha_short }}
|
||||||
steps:
|
steps:
|
||||||
@ -182,6 +222,8 @@ jobs:
|
|||||||
aws-region: ${{ env.DEJO_NODE_AWS_REGION }}
|
aws-region: ${{ env.DEJO_NODE_AWS_REGION }}
|
||||||
|
|
||||||
- name: Deploy API
|
- name: Deploy API
|
||||||
|
id: deploy_api
|
||||||
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.DEJO_NODE_KUBE_CONFIG_DATA_DEV }}" | base64 -d > kubeconfig
|
echo "${{ secrets.DEJO_NODE_KUBE_CONFIG_DATA_DEV }}" | base64 -d > kubeconfig
|
||||||
export KUBECONFIG=$PWD/kubeconfig
|
export KUBECONFIG=$PWD/kubeconfig
|
||||||
@ -189,24 +231,21 @@ jobs:
|
|||||||
${{ env.KUBE_DEPLOY_NAME }}="${{ secrets.DEV_DEJO_AWS_ECR_REGISTRY }}/${{ env.AWS_ECR_REPOSITORY }}:${{ env.sha_short }}" \
|
${{ env.KUBE_DEPLOY_NAME }}="${{ secrets.DEV_DEJO_AWS_ECR_REGISTRY }}/${{ env.AWS_ECR_REPOSITORY }}:${{ env.sha_short }}" \
|
||||||
--record -n "${KUBE_NAMESPACE}"
|
--record -n "${KUBE_NAMESPACE}"
|
||||||
|
|
||||||
- name: Verify Rollout
|
- name: Discord | Notify Error (Deploy)
|
||||||
run: |
|
if: steps.deploy_api.outcome == 'failure' && env.DISABLE_DISCORD_NOTIFY != 'true'
|
||||||
echo "${{ secrets.DEJO_NODE_KUBE_CONFIG_DATA_DEV }}" | base64 -d > kubeconfig
|
|
||||||
export KUBECONFIG=$PWD/kubeconfig
|
|
||||||
kubectl rollout status deployment/${{ env.KUBE_DEPLOY_NAME }} -n "${KUBE_NAMESPACE}"
|
|
||||||
|
|
||||||
- name: Discord | Notify Error
|
|
||||||
if: ${{ failure() && env.DISABLE_DISCORD_NOTIFY != 'true' }}
|
|
||||||
run: |
|
run: |
|
||||||
curl -X POST -H "Content-Type: application/json" \
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
-d '{"content":":x: Erro durante o deploy! Veja logs."}' \
|
-d '{"content":":x: Erro durante o deploy! Veja logs."}' \
|
||||||
"${{ env.DISCORD_WEBHOOK }}"
|
"${DISCORD_WEBHOOK}"
|
||||||
exit 1
|
|
||||||
|
|
||||||
- name: Discord | Notify Success
|
- name: Fail job if deploy_api failed
|
||||||
if: ${{ success() && env.DISABLE_DISCORD_NOTIFY != 'true' }}
|
if: steps.deploy_api.outcome == 'failure'
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- name: Discord | Notify Success (Deploy)
|
||||||
|
if: steps.deploy_api.outcome == 'success' && env.DISABLE_DISCORD_NOTIFY != 'true'
|
||||||
run: |
|
run: |
|
||||||
curl -X POST -H "Content-Type: application/json" \
|
curl -X POST -H "Content-Type: application/json" \
|
||||||
-d '{"content":":white_check_mark: Deploy concluído com sucesso! :rocket:"}' \
|
-d '{"content":":white_check_mark: Deploy concluído com sucesso! :rocket:"}' \
|
||||||
"${{ env.DISCORD_WEBHOOK }}"
|
"${DISCORD_WEBHOOK}"
|
||||||
|
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
# Local .terraform directories
|
# Local .terraform directories
|
||||||
### Terraform ###
|
### Terraform ###
|
||||||
|
data
|
||||||
**/.terraform/*
|
**/.terraform/*
|
||||||
*.tfstate
|
*.tfstate
|
||||||
*.tfstate.*
|
*.tfstate.*
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"branches": ["master"],
|
"branches": ["dev"],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
[
|
[
|
||||||
"@semantic-release/commit-analyzer",
|
"@semantic-release/commit-analyzer",
|
||||||
|
|||||||
44
CHANGELOG.md
44
CHANGELOG.md
@ -1,3 +1,39 @@
|
|||||||
|
# [1.6.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.5.0...v1.6.0) (2025-06-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* teste deploy Upgrade karpenter k8s v.027 para 1.20 ([bff2c0a](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/bff2c0abff5908cd03240c33ef0a6eb4b64b79ff))
|
||||||
|
|
||||||
|
# [1.5.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.4.0...v1.5.0) (2025-06-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 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))
|
||||||
|
|
||||||
|
# [1.3.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.2.0...v1.3.0) (2025-06-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
|
||||||
|
### 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)
|
# [1.1.0](https://git.dejodigital.com.br/dejo-core/dejo-node/compare/v1.0.0...v1.1.0) (2025-06-11)
|
||||||
|
|
||||||
|
|
||||||
@ -12,6 +48,14 @@
|
|||||||
|
|
||||||
### Features
|
### 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 ([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 ([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))
|
* CI/CD - Conventional Commits e Semantic Release ([abf3c77](https://git.dejodigital.com.br/dejo-core/dejo-node/commit/abf3c771e539afa48de8139ed7adb81341e80600))
|
||||||
|
|||||||
85
changelog.md
85
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
|
### 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))
|
||||||
|
|||||||
67
cmd/main.go
67
cmd/main.go
@ -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{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
// commitlint.config.js
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ['@commitlint/config-conventional']
|
extends: ['@commitlint/config-conventional']
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Index": 1,
|
|
||||||
"PrevHash": "genesis",
|
|
||||||
"Txns": [],
|
|
||||||
"Timestamp": 1746203588,
|
|
||||||
"Nonce": 0,
|
|
||||||
"Hash": "176b199bd82d6e6d22719cdc95709646433204f299b2f49efbba9985ee9eac4e"
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Index": 2,
|
|
||||||
"PrevHash": "176b199bd82d6e6d22719cdc95709646433204f299b2f49efbba9985ee9eac4e",
|
|
||||||
"Txns": [],
|
|
||||||
"Timestamp": 1746203596,
|
|
||||||
"Nonce": 0,
|
|
||||||
"Hash": "0af7272a293becc055d79604b96717e06be4e3ff8be65f1d65b6d1979b9d166c"
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Index": 3,
|
|
||||||
"PrevHash": "0af7272a293becc055d79604b96717e06be4e3ff8be65f1d65b6d1979b9d166c",
|
|
||||||
"Txns": [],
|
|
||||||
"Timestamp": 1746206836,
|
|
||||||
"Nonce": 0,
|
|
||||||
"Hash": "40186b92c0be8c1cd252b223dce51df3156a3fadd32e21f38db298e01da70f69"
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Index": 4,
|
|
||||||
"PrevHash": "40186b92c0be8c1cd252b223dce51df3156a3fadd32e21f38db298e01da70f69",
|
|
||||||
"Txns": [],
|
|
||||||
"Timestamp": 1746206844,
|
|
||||||
"Nonce": 0,
|
|
||||||
"Hash": "4519522e80850a467c571eccdbad3a9b078b75d0dd3c889a87725c207eff3464"
|
|
||||||
}
|
|
||||||
BIN
data/staking.db
BIN
data/staking.db
Binary file not shown.
BIN
data/state.gob
BIN
data/state.gob
Binary file not shown.
6
go.mod
6
go.mod
@ -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
16
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/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=
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
@ -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 {
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
@ -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)))
|
||||||
}
|
}
|
||||||
@ -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")
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
@ -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})
|
||||||
}
|
}
|
||||||
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,8 +12,7 @@ type RoundState struct {
|
|||||||
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.
|
||||||
@ -32,8 +30,6 @@ func NewRoundState(height uint64) *RoundState {
|
|||||||
|
|
||||||
// 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)
|
||||||
|
|||||||
@ -15,6 +15,7 @@ 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)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user