Files
dejo-node/internal/miner/miner.go
2025-05-23 10:44:32 -03:00

76 lines
1.7 KiB
Go

package miner
import (
"dejo_node/internal/consensus"
"dejo_node/internal/storage"
"dejo_node/internal/transactions"
"dejo_node/internal/ws"
"fmt"
"time"
)
// Miner representa o componente responsável por propor blocos válidos.
type Miner struct {
Engine consensus.Engine
BlockStore *storage.BlockStore
Mempool *transactions.Mempool
}
// New cria uma nova instância de minerador
func New(engine consensus.Engine, store *storage.BlockStore, mempool *transactions.Mempool) *Miner {
return &Miner{
Engine: engine,
BlockStore: store,
Mempool: mempool,
}
}
// MineNextBlock propõe, valida e armazena um novo bloco se possível
func (m *Miner) MineNextBlock() (*transactions.Block, error) {
if !m.Engine.CanPropose() {
return nil, fmt.Errorf("este nó não tem permissão para propor blocos")
}
txns := m.Mempool.Pending()
if len(txns) == 0 {
return nil, fmt.Errorf("nenhuma transação pendente para minerar")
}
lastBlock, err := m.BlockStore.GetLatestBlock()
index := uint64(0)
prevHash := ""
if err == nil {
index = lastBlock.Index + 1
prevHash = lastBlock.Hash
}
blk := &transactions.Block{
Index: index,
Timestamp: time.Now().Unix(),
PrevHash: prevHash,
Txns: txns,
}
blk.ComputeHash()
if err := m.Engine.Finalize(blk); err != nil {
return nil, fmt.Errorf("bloco rejeitado pelo consenso: %w", err)
}
if err := m.BlockStore.SaveBlock(blk); err != nil {
return nil, fmt.Errorf("erro ao salvar bloco: %w", err)
}
// Emitir eventos WebSocket
ws.Emit("newBlock", map[string]any{
"index": blk.Index,
"hash": blk.Hash,
})
for _, tx := range blk.Txns {
ws.Emit("txConfirmed", map[string]any{
"hash": tx.Hash(),
})
}
m.Mempool.Clear()
return blk, nil
}