CometBFT에서는 높이마다 제안자(proposer)가 블록을 내놓고, 검증자가 사전 투표(prevote)와 사전 확정 투표(precommit)를 보냅니다. 한 라운드에서 특정 블록에 +2/3 prevote가 모이면 검증자는 그 블록을 잠그고 precommit할 수 있고, +2/3 precommit이 모이면 블록이 커밋됩니다. 제안이 없거나 유효하지 않으면 nil 투표와 시간 초과를 거쳐 다음 라운드로 넘어갑니다. 잠금(lock)은 지연이 생긴 사이 서로 다른 블록이 쉽게 확정되지 않게 막는 안전장치입니다.
높이와 라운드부터 나눠 봅니다
높이(height)는 다음 블록이 들어갈 자리이고, 라운드(round)는 그 높이에서 합의를 시도한 횟수입니다. 네트워크가 늦거나 제안자에게 장애가 생기면 같은 높이에서 round 0, 1, 2로 넘어갈 수 있습니다. 라운드가 늘었다고 체인이 재구성됐거나 블록 높이가 올라갔다고 읽어서는 안 됩니다. 라운드마다 제안자와 시간 제한이 새로 정해집니다.
제안 단계에서 지정된 제안자는 블록과, 가능하면 이전 라운드의 다수 증거를 함께 내놓습니다. 검증자는 제안의 기본 유효성과 애플리케이션 검사를 거친 뒤 사전 투표를 합니다. 유효한 제안을 제때 받지 못했거나 조건이 맞지 않으면 nil에 사전 투표할 수 있습니다. nil은 서버가 아무 메시지도 안 보냈다는 뜻이 아니라 특정 블록에 동의하지 않는다는 분명한 투표입니다.
라운드는 실패를 세는 표가 아닙니다. 같은 높이에서 안전한 제안을 다시 모으는 합의의 시간축입니다.
JOBCOIN 해설

그림은 이 주제의 공통 개념을 단순화한 설명입니다. 아래 항목에서 이 글의 구체적인 조건과 예외를 함께 읽어보세요.
- 높이와 라운드부터 나눠 봅니다
높이(height)는 다음 블록이 들어갈 자리이고, 라운드(round)는 그 높이에서 합의를 시도한 횟수입니다.
- 두 투표는 묻는 질문이 다릅니다
사전 투표는 이번 라운드에서 어떤 제안을 지지할 수 있는지 드러냅니다.
- 잠금이 서로 다른 라운드를 이어 줍니다
검증자가 한 라운드에서 블록을 잠갔다면 다음 라운드의 새 제안을 무조건 따르지 않습니다.
설명을 위한 개념도 · 실제 가격·거래 내역·통계가 아닙니다.
두 투표는 묻는 질문이 다릅니다
사전 투표는 이번 라운드에서 어떤 제안을 지지할 수 있는지 드러냅니다. 특정 블록 ID에 투표권 기준 +2/3를 넘는 사전 투표, 이른바 폴카(polka)가 모이면 검증자는 조건에 따라 그 블록을 잠그고 사전 확정 투표를 합니다. +2/3가 어느 블록에도 모이지 않으면 nil 사전 확정 투표와 시간 초과를 거쳐 다음 라운드로 갈 수 있습니다.
사전 확정 투표는 커밋에 한 걸음 더 다가선 단계입니다. 같은 블록 ID에 +2/3 precommit이 모이면 노드는 그 블록을 커밋하고 다음 높이로 넘어갑니다. 2/3라는 숫자를 검증자 계정 수로 세면 안 됩니다. 100개 검증자 가운데 40개가 큰 투표권을 쥐고 있다면, 계정 수로는 소수여도 결과를 크게 좌우할 수 있습니다.
| 단계 | 핵심 입력 | 가능한 결과 |
|---|---|---|
| 제안 | 제안자의 블록·POL | 제안 수신 또는 시간 초과 |
| 사전 투표 | 유효 제안·현재 잠금 | 블록 ID 또는 nil 투표 |
| 사전 확정 | +2/3 prevote 증거 | 블록 잠금·nil 사전 확정 |
| 커밋 | +2/3 precommit | 블록 확정 후 다음 높이 |
잠금이 서로 다른 라운드를 이어 줍니다
검증자가 한 라운드에서 블록을 잠갔다면 다음 라운드의 새 제안을 무조건 따르지 않습니다. 더 높은 라운드에서 알맞은 +2/3 prevote 증거를 보는 식의 잠금 해제 조건이 있어야 합니다. 이 기억 장치가 없으면 지연된 검증자 무리가 서로 다른 제안을 각자 확정할 위험이 커집니다.
validBlock과 validRound는 제안자가 이전 라운드에서 다수 사전 투표를 얻은 블록을 다시 제안할 때 쓰입니다. 다른 검증자는 제안에 담긴 POLRound를 보고 새 제안이 과거 증거와 어떻게 이어지는지 판단합니다. 잠금은 영원히 멈춰 서는 장치가 아니라 다수 증거를 따라 안전하게 옮겨 가기 위한 제약입니다.
- 로그를 높이·라운드·단계 세 축으로 정렬합니다
- 투표 개수가 아니라 검증자 투표권 합계를 계산합니다
- 블록 ID 투표와 nil 투표를 단계별로 따로 셉니다
- lockedRound·validRound·제안의 POLRound가 어떤 순서로 바뀌었는지 확인합니다
진행이 멈춘 것과 안전이 깨진 것은 다른 말입니다
+2/3 precommit이 모이지 않으면 그 라운드의 커밋은 늦어집니다. 하지만 서로 충돌하는 블록이 확정됐다는 뜻은 아닙니다. 네트워크 분할, 대량의 오프라인 투표권, 느린 제안 전파는 진행을 방해할 수 있습니다. 반대로 비잔틴(Byzantine) 검증자가 중복 투표를 보내면 증거 제출과 처벌 절차의 대상이 될 수 있습니다.
장애를 분석할 때는 라운드 소요 시간, 제안 수신, 두 투표의 투표권 합계, 피어 연결을 함께 봅니다. 시간 초과를 너무 짧게 잡으면 평범한 지연에도 라운드 전환이 잦아지고, 너무 길게 잡으면 장애에서 늦게 회복합니다. 체인별 설정과 실제 지연 분포를 모른 채 누구에게나 맞는 최적값을 내놓을 수는 없습니다.
탐색기 화면보다 합의 로그가 더 많은 것을 알려 줍니다
탐색기는 최종 높이와 블록 해시를 보여 주지만, 그 앞에 라운드가 몇 번 돌았고 어떤 nil 투표가 오갔는지는 빠뜨릴 수 있습니다. 블록 시간이 길어진 이유를 찾으려면 CometBFT 합의 로그와 RPC consensus_state, 검증자 세트를 같은 높이에서 맞춰 봐야 합니다. 애플리케이션 처리 지연과 합의 메시지 지연도 구분합니다.
정확하게 설명하려면 제안, 두 투표, 잠금, 커밋을 차례대로 놓아야 합니다. +2/3 prevote가 곧바로 블록 커밋은 아니고, +2/3 precommit이 커밋 조건입니다. 다음 라운드의 새 제안이 이전 잠금을 지우라는 명령도 아닙니다. 이 세 경계만 지켜도 평범한 라운드 전환을 포크 사고로 부풀리지 않습니다. 서로 다른 합의 방식의 라운드 구조를 비교할 때는 Sui Mysticeti 전환처럼 예전 엔진과 지금 엔진을 시기별로 나눠야 용어를 엉뚱하게 옮겨 쓰지 않습니다.
자주 묻는 질문
+2/3는 검증자 인원수인가요?
아닙니다. CometBFT 합의의 기준선은 검증자 투표권 합계로 셉니다.
+2/3 prevote가 모이면 블록이 바로 커밋되나요?
아닙니다. 잠금과 사전 확정 단계가 뒤따르고, 같은 블록에 +2/3 precommit이 모여야 커밋됩니다.
nil 투표는 검증자가 오프라인이라는 뜻인가요?
꼭 그렇지는 않습니다. 유효한 제안을 받지 못했거나 잠금 조건 때문에 특정 블록을 지지하지 않겠다는 분명한 투표일 수 있습니다.
더 깊이 읽기
본문에서 다룬 개념과 확인 절차를 다음 글에서 이어서 살펴보세요.



