PBFT: Tolerancia a Fallos Bizantinos
En el universo de KodeChain, donde la confianza absoluta es fundamental, el algoritmo Practical Byzantine Fault Tolerance (PBFT) emerge como el guardián de la verdad para registros críticos. Esta guía revela cómo el código en consensus/pbft.go transforma principios matemáticos complejos en un sistema robusto de validación distribuida.
La Ciencia Detrás de PBFT
Tolerancia a Fallos Bizantinos
PBFT resuelve el problema más desafiante en sistemas distribuidos: ¿cómo mantener la consistencia cuando algunos participantes pueden comportarse de manera maliciosa o fallar arbitrariamente? A diferencia de otros algoritmos que requieren suposiciones simplistas sobre fallos, PBFT tolera hasta f nodos fallidos en un sistema de 3f+1 nodos totales.
// En pbft.go, línea 76
config := &PBFTConfig{
Timeout: 10 * time.Second,
CheckpointPeriod: 100,
WatermarkPeriod: 1000,
MaxFaultyNodes: 1, // Puede tolerar 1 nodo fallido
ViewChangeTimeout: 30 * time.Second,
}
Arquitectura del Sistema PBFT
El Núcleo: Estructura PBFT
type PBFT struct {
NodeID string
Primary string // Nodo líder actual
Validators []string // Lista de validadores
BlockStates map[string]*PBFTState // Estados por bloque
View uint64 // Número de vista actual
SequenceNumber uint64 // Número de secuencia
Broadcaster MessageBroadcaster
Signer security.Signer // Firmas post-cuánticas
// ... más campos
}
Cada instancia PBFT mantiene un estado completo del protocolo, incluyendo el seguimiento de mensajes de consenso para cada bloque.
Estados de Bloque
type PBFTState struct {
Block *blockchain.Block `json:"block"`
PrePrepared bool `json:"prePrepared"`
PrepareCount int `json:"prepareCount"`
CommitCount int `json:"commitCount"`
Prepared bool `json:"prepared"`
Committed bool `json:"committed"`
PreparedBy map[string]bool `json:"preparedBy"`
CommittedBy map[string]bool `json:"committedBy"`
ViewChangeCount int `json:"viewChangeCount"`
}
El Protocolo de Tres Fases
Fase 1: Pre-Prepare
El nodo primario inicia el consenso enviando un mensaje pre-prepare a todos los validadores:
func (p *PBFT) initiateConsensus(block *blockchain.Block) error {
p.SequenceNumber++
prePrepare := &PBFTPrePrepare{
Block: block,
View: p.View,
Digest: block.Hash,
}
if p.Broadcaster != nil {
if err := p.Broadcaster.Broadcast(prePrepare); err != nil {
return fmt.Errorf("error enviando pre-prepare: %v", err)
}
}
utils.LogInfo("PBFT: Consenso iniciado para bloque %s, secuencia %d", block.Hash, p.SequenceNumber)
return nil
}
Fase 2: Prepare
Los validadores verifican el bloque y envían mensajes prepare:
func (p *PBFT) handlePrepare(block *blockchain.Block, nodeID string) error {
state := p.GetBlockState(block)
p.mutex.Lock()
defer p.mutex.Unlock()
if state.PreparedBy[nodeID] {
return nil // Ya preparado por este nodo
}
state.PreparedBy[nodeID] = true
state.PrepareCount++
utils.LogInfo("Received prepare for block %s from node %s (%d/%d)",
block.Hash, nodeID, state.PrepareCount, len(p.Validators))
threshold := 2 * len(p.Validators) / 3
if state.PrepareCount >= threshold && !state.Prepared {
state.Prepared = true
utils.LogInfo("Block %s prepared with %d votes", block.Hash, state.PrepareCount)
return p.BroadcastCommit(block)
}
return nil
}
Fase 3: Commit
Una vez alcanzado el quórum de prepare, los validadores envían commit:
func (p *PBFT) handleCommit(block *blockchain.Block, nodeID string) error {
state := p.GetBlockState(block)
p.mutex.Lock()
defer p.mutex.Unlock()
if state.CommittedBy[nodeID] {
return nil // Ya comprometido por este nodo
}
state.CommittedBy[nodeID] = true
state.CommitCount++
utils.LogInfo("Received commit for block %s from node %s (%d/%d)",
block.Hash, nodeID, state.CommitCount, len(p.Validators))
threshold := 2 * len(p.Validators) / 3
if state.CommitCount >= threshold && !state.Committed {
state.Committed = true
utils.LogInfo("Block %s committed with %d votes", block.Hash, state.CommitCount)
if p.onBlockCommitted != nil {
p.onBlockCommitted(block)
}
}
return nil
}
Registros Críticos: El Caso de Uso Especializado
Arquitectura de Registros Críticos
PBFT en KodeChain está especializado para validar registros críticos no económicos:
type CriticalRecord struct {
ID string `json:"id"`
Type string `json:"type"` // DOCUMENT, AUDIT, LEGAL, etc.
DocumentHash string `json:"documentHash"`
Timestamp time.Time `json:"timestamp"`
ValidatorID string `json:"validatorId"`
Status string `json:"status"` // PENDING, COMMITTED, REJECTED
Data []byte `json:"data"`
Signature string `json:"signature"`
}
Validación de Registros
func (p *PBFT) ValidateCriticalRecord(record *CriticalRecord) bool {
// Rechazar registros económicos - PBFT solo maneja críticos
if record.Type == "ECONOMIC" {
utils.LogWarning("PBFT: Rejecting economic record - PBFT only handles critical records")
return false
}
// Validar estructura
if record.DocumentHash == "" || record.Timestamp.IsZero() {
utils.LogWarning("PBFT: Invalid record structure")
return false
}
// Verificar permisos por tipo
if !p.hasPermissionForRecordType(record.Type) {
utils.LogWarning("PBFT: Validator lacks permission for record type: %s", record.Type)
return false
}
// Validar firma
if !p.validateRecordSignature(record) {
utils.LogWarning("PBFT: Invalid record signature")
return false
}
return true
}
Tipos de Registro Permitidos
allowedTypes := []string{
"DOCUMENT", // Documentos legales
"AUDIT", // Auditorías
"LEGAL", // Registros legales
"CERTIFICATE", // Certificados
"PATENT", // Patentes
"TRADEMARK", // Marcas registradas
"CONTRACT", // Contratos
"COMPLIANCE", // Cumplimiento regulatorio
}
Minería Automática de Bloques
El Block Miner PBFT
type PBFTBlockMiner struct {
pbft *PBFT
mempool interface{}
blockchain interface{}
checkInterval time.Duration
isMining bool
minTransactions int
maxBlockTime time.Duration
lastBlockTime time.Time
}
Lógica de Minería
func (bm *PBFTBlockMiner) checkAndMineBlock() {
if !bm.pbft.IsRunning() {
return
}
transactions := bm.getPendingTransactions()
if len(transactions) == 0 {
return
}
shouldMine := bm.shouldCreateBlock(len(transactions))
if !shouldMine {
return
}
block, err := bm.createBlock(transactions)
if err != nil {
utils.LogError("PBFT Block Miner: Error creating block: %v", err)
return
}
if err := bm.startPBFTConsensus(block); err != nil {
utils.LogError("PBFT Block Miner: Error starting consensus: %v", err)
return
}
}
Gestión de Vistas y Recuperación
Cambios de Vista
Cuando el nodo primario falla, el sistema inicia un cambio de vista:
func (p *PBFT) InitiateViewChange() error {
p.mutex.Lock()
p.View++
newView := p.View
p.mutex.Unlock()
utils.LogInfo("Initiated view change to view %d", newView)
return nil
}
Procesamiento de Cambios de Vista
func (p *PBFT) handleViewChangeMessage(message *PBFTMessage) error {
viewChangeData, ok := message.Data.(*PBFTViewChange)
if !ok {
return fmt.Errorf("formato de mensaje view-change inválido")
}
if _, exists := p.viewChanges[message.NodeID]; !exists {
p.viewChanges[message.NodeID] = make(map[uint64]int)
}
p.viewChanges[message.NodeID][viewChangeData.NewView]++
viewCount := 0
for _, nodeViews := range p.viewChanges {
if count, exists := nodeViews[viewChangeData.NewView]; exists {
viewCount += count
}
}
threshold := 2 * len(p.Validators) / 3
if viewCount >= threshold && viewChangeData.NewView > p.View {
p.View = viewChangeData.NewView
if len(p.Validators) > 0 {
p.Primary = p.Validators[int(p.View)%len(p.Validators)]
}
utils.LogInfo("PBFT: Vista cambiada a %d. Nuevo primario: %s", p.View, p.Primary)
}
return nil
}
Integración con Staking
Fees Mensuales
PBFT incluye un sistema de fees mensuales para uso de registros críticos:
func (p *PBFT) ProcessMonthlyFee(validatorAddress string, feeAmount uint64) error {
if !slices.Contains(p.Validators, validatorAddress) {
return fmt.Errorf("validator not active")
}
if p.stakingContract != nil {
if staking, ok := p.stakingContract.(interface {
ProcessMonthlyFee(validatorAddress string, feeAmount uint64, serviceType string) error
}); ok {
return staking.ProcessMonthlyFee(validatorAddress, feeAmount, "PBFT_CRITICAL_RECORDS")
}
}
utils.LogInfo("PBFT: Monthly fee processed for validator %s: %d", validatorAddress, feeAmount)
return nil
}
Métricas y Monitoreo
Métricas del Sistema PBFT
type PBFTMetrics struct {
ViewNumber uint64
SequenceNumber uint64
Checkpoint uint64
Watermark uint64
TotalBlocks uint64
CommittedBlocks uint64
ViewChanges uint64
PrimaryChanges uint64
AverageLatency time.Duration
FaultyNodes uint64
}
Recolección de Métricas
func (p *PBFT) GetMetrics() *PBFTMetrics {
p.mutex.RLock()
defer p.mutex.RUnlock()
return &PBFTMetrics{
ViewNumber: p.View,
SequenceNumber: p.SequenceNumber,
Checkpoint: p.checkpoint,
Watermark: p.watermark,
TotalBlocks: uint64(len(p.BlockStates)),
CommittedBlocks: p.countCommittedBlocks(),
ViewChanges: p.countViewChanges(),
}
}
Seguridad Post-Cuántica
Firmas en PBFT
Todos los mensajes PBFT están firmados con ML-DSA-65:
func NewPBFT(broadcaster MessageBroadcaster, logger Logger) *PBFT {
qs, err := security.NewQuantumSigner()
if err != nil {
panic("No se pudo inicializar QuantumSigner: " + err.Error())
}
return &PBFT{
Signer: qs,
// ... otros campos
}
}
El Futuro de PBFT en KodeChain
PBFT representa la evolución de la tolerancia a fallos bizantinos, adaptada específicamente para el mundo post-cuántico. Su especialización en registros críticos, combinada con la robustez matemática del algoritmo original, crea un sistema que puede resistir no solo fallos técnicos, sino también ataques sofisticados.
Cada línea de código en consensus/pbft.go está diseñada para mantener la integridad de los registros más críticos de la sociedad digital, desde contratos legales hasta certificados oficiales, asegurando que la verdad prevalezca incluso en presencia de adversarios maliciosos.