Разработка кастомного консенсус-механизма
Большинство проектов, которые приходят с запросом "разработайте нам свой консенсус", на самом деле не нуждаются в кастомном консенсусе. Им нужен application-specific chain с модифицированными параметрами: другой block time, другие правила включения транзакций, кастомный mempool. Это решается через Cosmos SDK или OP Stack без написания нового консенсусного протокола. Настоящий кастомный консенсус — это 1–2 года работы команды из опытных distributed systems инженеров и формальная верификация корректности. Это важно понять до начала технического обсуждения.
Когда реально нужен кастомный консенсус
Легитимные случаи: специализированная сеть с нестандартными требованиями к производительности (> 100k TPS, deterministic finality < 100мс), консорциумные сети с кастомными правилами валидации участников, исследовательские/академические проекты, экспериментальные механизмы (VDF-based randomness, threshold signatures as consensus).
В большинстве случаев проще взять существующий алгоритм и адаптировать его. Разберём архитектурное пространство выбора.
Taxonomy консенсусных протоколов
Classical BFT: pBFT и производные
pBFT (Practical Byzantine Fault Tolerance, Castro & Liskov, 1999) — первый практичный BFT алгоритм. O(n²) сообщений, работает при < n/3 Byzantine nodes. В чистом виде не масштабируется за ~20 nodes из-за communication overhead.
Современные производные:
- HotStuff (используется в LibraBFT/DiemBFT/Jolteon): линейная коммуникационная сложность O(n), лидерская схема с pipelining. Facebook/Meta использовали для Diem.
- Tendermint/CometBFT: round-based, deterministic finality per block, используется в Cosmos SDK. Два фазы: prevote и precommit. Требует > 2/3 voting power для finality.
- PBFT с threshold signatures: заменяем n²-коммуникацию агрегацией через BLS threshold signatures — каждый валидатор подписывает BLS ключом, агрегатор собирает threshold подписей в одну.
Nakamoto Consensus и производные
PoW Nakamoto — probabilistic finality, fork choice rule (longest chain / most work). Никогда не финален, но практически необратим после достаточного числа подтверждений. Простота — главное преимущество.
GHOST protocol (Greedy Heaviest-Observed Subtree): fork choice учитывает uncle blocks, не только main chain. Используется в Ethereum (Gasper — комбинация GHOST + Casper FFG).
Proof-of-Stake variants: в PoS "вычислительная работа" заменяется стейком. Validator selection через VRF (Verifiable Random Function) — Algorand, Cardano Ouroboros.
DAG-based консенсус
Hashgraph (Hedera): события организованы в DAG, виртуальное голосование без сообщений. Детерминированный алгоритм из DAG-структуры вычисляет consensus timestamp и order.
Narwhal/Bullshark (Sui): Narwhal — DAG-based mempool с certified availability (каждый блок сертифицируется 2f+1 подписями). Bullshark — интерпретирует DAG для ordering. Разделение data dissemination и ordering.
Mysticeti (новый консенсус Sui): убирает лидера из критического пути, снижает latency.
Реализация: пример HotStuff-inspired протокола
Рассмотрим ключевые компоненты при реализации BFT-консенсуса на Go:
Структуры данных
type Block struct {
Height uint64
ParentHash [32]byte
Txns []Transaction
QC *QuorumCertificate //証明 предыдущего блока
Timestamp int64
ProposerID NodeID
}
type QuorumCertificate struct {
BlockHash [32]byte
Height uint64
Signatures []BLSSignature // threshold агрегированная подпись
Signers []NodeID
}
type Vote struct {
BlockHash [32]byte
Height uint64
Round uint32
VoterID NodeID
Signature BLSSignature
}
Три фазы HotStuff
HotStuff организует консенсус в трёх фазах (prepare, pre-commit, commit) с pipelining — пока блок k проходит commit, блок k+1 проходит pre-commit, блок k+2 — prepare:
type HotStuffNode struct {
id NodeID
height uint64
lockedQC *QuorumCertificate // locked на pre-commit фазе
preparedQC *QuorumCertificate // prepared на prepare фазе
privateKey bls.PrivateKey
validators ValidatorSet
}
func (n *HotStuffNode) onReceiveProposal(block *Block) {
// Safety rule: принять только если block.QC >= n.lockedQC
if block.QC.Height < n.lockedQC.Height {
return // отклоняем
}
// Liveness rule: принять если block.QC >= n.preparedQC
// или block расширяет locked block
if !n.safeNode(block) {
return
}
vote := n.createVote(block)
n.sendToleader(vote)
}
func (n *HotStuffNode) safeNode(block *Block) bool {
// Extends locked branch OR QC выше чем lockedQC
return block.QC.Height > n.lockedQC.Height ||
n.extendsLockedBlock(block)
}
BLS threshold signatures
Агрегация подписей через BLS12-381 кривую — стандарт для современных BFT протоколов. Threshold scheme (t из n): каждый validator подписывает своим ключом, агрегатор собирает t подписей и создаёт одну агрегированную подпись, верифицируемую одним публичным ключом:
import "github.com/herumi/bls-eth-go-binary/bls"
func aggregateSignatures(sigs []bls.Sign) bls.Sign {
var agg bls.Sign
agg.Add(&sigs[0])
for i := 1; i < len(sigs); i++ {
agg.Add(&sigs[i])
}
return agg
}
func verifyQC(qc *QuorumCertificate, validators ValidatorSet) bool {
pubkeys := make([]bls.PublicKey, len(qc.Signers))
for i, id := range qc.Signers {
pubkeys[i] = validators.GetPublicKey(id)
}
aggPubkey := bls.AggregatePubkeys(pubkeys)
return qc.Signatures[0].VerifyHash(&aggPubkey, qc.BlockHash[:])
}
View Change: обработка сбоев лидера
Liveness под Byzantine lider — сложнейший аспект. В HotStuff view change происходит при timeout:
func (n *HotStuffNode) onTimeout(view uint32) {
// Broadcast timeout message с текущим lockedQC
timeout := TimeoutMsg{
View: view,
LockedQC: n.lockedQC,
SenderID: n.id,
Sig: n.sign(view, n.lockedQC),
}
n.broadcast(timeout)
}
func (n *HotStuffNode) onReceiveTimeouts(timeouts []TimeoutMsg) {
if len(timeouts) < n.validators.QuorumSize() {
return
}
// Новый лидер — node с наибольшим view в round-robin или VRF
newLeader := n.electLeader(timeouts[0].View + 1)
if newLeader == n.id {
// Выбираем самый высокий QC из timeout messages
highQC := n.highestQC(timeouts)
n.proposeBlock(highQC)
}
}
Формальная верификация
Для production консенсусного протокола — обязательна формальная верификация safety и liveness properties. Инструменты:
TLA+ — язык формальной спецификации. Специфицируем safety invariant: "два честных узла не могут закоммитить разные блоки на одной высоте". TLC model checker проверяет на всех достижимых состояниях при n ≤ 5–7 nodes.
Ivy — язык для верификации distributed protocols. Команда Hedera использовала для Hashgraph. Coq/Lean — для proof assistant подхода.
Без формальной верификации кастомный консенсус не должен использоваться в production с реальными активами. История blockchain полна примеров консенсусных багов, обнаруженных годами позже (Ethereum Byzantium fork bugs, недавние Cosmos SDK консенсусные уязвимости).
Сетевой уровень: P2P transport
Консенсусные сообщения требуют low-latency доставки. Protobuf сериализация обязательна (JSON слишком медленный для consensus-critical messages). Transport:
libp2p — стандарт де-факто в Web3. GossipSub для broadcast, Direct streams для unicast. Используется в Ethereum, Filecoin, Polkadot.
QUIC/gRPC — для более контролируемых P2P топологий (enterprise blockchain).
Стек и сроки
Язык реализации: Go (Tendermint, Ethereum CL) или Rust (Solana, NEAR, Polkadot substrate) — оба имеют зрелые BLS libraries и p2p стеки.
Реалистичные этапы:
- Спецификация и формальная модель в TLA+: 4–6 недель
- Базовая реализация happy path: 8–12 недель
- View change и Byzantine fault handling: 8–12 недель
- Тестирование (chaos testing, Byzantine fault injection): 8–12 недель
- Formal verification: 4–8 недель
- Security audit: 6–8 недель
Итого: 10–18 месяцев до production-ready консенсуса. Адаптация существующего (CometBFT/HotStuff reference impl) с кастомными параметрами — 3–6 месяцев.







