76 lines
1.7 KiB
Go
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
|
|
} |