Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 193 additions & 0 deletions doc/crown/PHASE2_CONSENSUS_STATE_MACHINE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# Crown Successor PoC Phase 2

## Scope

Phase 2 adds an isolated native Crown consensus state machine that operates on abstract `BlockID` values (`uint256`) and remains disconnected from live Bitcoin block production, fork choice, validation, and P2P message handling.

Implemented:

- deterministic proposer rotation over the four static Phase 1 validators
- signed proposals and signed `PREVOTE` / `PRECOMMIT` messages
- explicit `NIL` voting via absent vote `block_id`
- exact voting-power quorum reuse from Phase 1
- one-height event-driven round progression across `PROPOSE`, `PREVOTE`, `PRECOMMIT`, and `COMMIT`
- Tendermint-style lock tracking with `locked_block` / `locked_round`
- `valid_block` / `valid_round` tracking and proposal handling
- equivocation detection for conflicting votes
- logical local double-sign protection for the in-process signer
- deterministic in-process multi-validator simulation tests

Deferred:

- live Bitcoin `CBlock` proposal and validation integration
- `net_processing.cpp` or live consensus P2P messages
- production finality certificates
- persistent crash-safe signing state
- staking, delegation, dynamic validator sets, and slashing economics

## State machine

Each engine models a single consensus height with:

- `height`
- `round`
- `step`
- `locked_block`
- `locked_round`
- `valid_block`
- `valid_round`
- the current round proposal
- an optional `CommitDecision`

Round changes do not reset the height. `PRECOMMIT_TIMEOUT` advances from round `r` to round `r+1` while preserving lock and valid-round state.

## Proposals

`Proposal` contains:

- `height`
- `round`
- proposer validator id
- proposed `BlockID`
- `valid_round`
- signature

The provisional proposer rule is deterministic rotation in static validator order:

1. `validator-a`
2. `validator-b`
3. `validator-c`
4. `validator-d`

Round `r` uses proposer index `r mod 4`.

The engine rejects proposals with:

- unknown proposer id
- proposer mismatch for the round
- invalid signature
- wrong height
- wrong round
- missing `BlockID`
- malformed `valid_round`

## Votes

`Vote` contains:

- vote type (`PREVOTE` or `PRECOMMIT`)
- `height`
- `round`
- validator id
- `BlockID` or explicit `NIL`
- signature

Canonical signing bytes are deterministic hash inputs over message domain, vote/proposal metadata, validator identity, and the optional block value. Unknown validators and invalid signatures contribute zero voting power.

## NIL semantics

`NIL` is a first-class consensus value used when:

- a proposal is missing
- a proposal is externally marked invalid
- a proposal conflicts with the local lock and does not carry sufficient `valid_round` proof
- timeout progression requires voting without a valid block

`PREVOTE(NIL)` and `PRECOMMIT(NIL)` advance the protocol without committing a block.

## Quorum rule

Phase 2 reuses the Phase 1 exact power model:

- total power = `100`
- quorum threshold = `floor(2 * total_power / 3) + 1 = 67`

Any three validators provide `75` power and satisfy quorum. Two validators provide `50` power and do not.

Duplicate identical votes are counted once. Conflicting votes from the same validator never both count.

## Locking semantics

The engine locks when it observes `>2/3` `PREVOTE`s for a concrete block in the current round and then emits `PRECOMMIT(block)`.

While locked on block `X`, the engine:

- may `PREVOTE(X)` again in later rounds
- must not `PREVOTE(Y)` for conflicting `Y` without sufficient `valid_round` evidence
- may `PREVOTE(NIL)` if a conflicting proposal lacks such evidence

The lock changes only after the engine sees a later-round `PREVOTE` quorum for another block and then emits `PRECOMMIT` for that later block.

## `valid_round` semantics

When the engine observes `>2/3` `PREVOTE`s for block `B` in round `r`, it stores:

- `valid_block = B`
- `valid_round = r`

A later proposal for `B` may reference that `valid_round`. If the local node is locked on another block from an earlier round, and it has stored proof of the referenced `PREVOTE` quorum, it may safely `PREVOTE(B)` in the later round.

## Timeout events

Phase 2 uses deterministic timeout events instead of real clocks:

- `PROPOSE_TIMEOUT`
- `PREVOTE_TIMEOUT`
- `PRECOMMIT_TIMEOUT`

`PROPOSE_TIMEOUT` drives `PREVOTE(NIL)` when needed. `PREVOTE_TIMEOUT` drives `PRECOMMIT(NIL)` when needed. `PRECOMMIT_TIMEOUT` starts the next round.

## Equivocation detection

The engine records evidence when a validator sends conflicting votes for the same:

- height
- round
- vote type

Evidence is exposed as paired conflicting votes and is suitable for later slashing integration. Phase 2 does not implement economics or punishment.

## Local double-sign protection

The local in-process signer refuses to produce two different votes for the same:

- height
- round
- vote type

This is a logical guard only. Persistent crash-safe signing state is deferred. Production validator safety still requires durable signing-state persistence before any live multi-process deployment.

## Simulator and tests

The Phase 2 unit tests instantiate four local engines and deliver:

- proposals
- votes
- timeouts
- delayed messages
- dropped messages
- 3/1 and 2/2 partitions
- conflicting Byzantine vote messages
- deterministic message-order permutations

The simulator enforces the invariant that no two honest engines may commit different block ids at the same height.

Tested scenarios include:

- 4/4, 3/4, and 2/4 availability thresholds
- offline proposer round change
- invalid proposals
- duplicate, stale, wrong-height, unknown-validator, and bad-signature votes
- `NIL` quorum handling
- prevote and precommit equivocation
- lock retention and valid-round transitions
- partition behavior
- deterministic message-order permutations

## Known Phase 2 limitations

- Consensus operates on abstract `BlockID` values only.
- No Bitcoin chainstate, mempool, miner, wallet, or script code is modified.
- No live proposal/vote networking exists.
- No persistent signer state exists yet.
- Only the static Phase 1 validator set is supported.
41 changes: 41 additions & 0 deletions doc/crown/SUCCESSOR_POC_PATCH_SURFACE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Crown Successor PoC Patch Surface

## Scope

This file tracks the incremental patch surface beyond the Phase 1 baseline documented in `doc/crown/phase1-network-validator-scaffold.md`.

Phase 2 remains overwhelmingly isolated to new Crown-owned files plus minimal build/test wiring.

## New Crown-owned files added in Phase 2

| File | Reason | Classification | Merge risk |
| --- | --- | --- | --- |
| `src/crown/consensus/types.h` | Declares Phase 2 consensus message/state types, `BlockID`, timeout enums, equivocation evidence, and commit results. | New isolated Crown module | Low |
| `src/crown/consensus/types.cpp` | Implements deterministic signing hashes plus proposal/vote signing and verification against the static validator set. | New isolated Crown module | Low |
| `src/crown/consensus/engine.h` | Declares the event-driven one-height consensus engine, state, and emitted actions. | New isolated Crown module | Low |
| `src/crown/consensus/engine.cpp` | Implements proposer checks, quorum handling, locking, valid-round handling, equivocation detection, round changes, and local double-sign guard logic. | New isolated Crown module | Low |
| `src/test/crown_consensus_tests.cpp` | Adds deterministic multi-validator simulation and Phase 2 unit coverage. | Crown-specific test | Low |
| `doc/crown/PHASE2_CONSENSUS_STATE_MACHINE.md` | Documents the implemented Phase 2 consensus behavior and deferred items. | Crown documentation | Low |
| `doc/crown/SUCCESSOR_POC_PATCH_SURFACE.md` | Tracks the cumulative PoC patch surface starting from the Phase 1 baseline. | Crown documentation | Low |

## Existing upstream Bitcoin files modified in Phase 2

| File | Reason | Classification | Merge risk |
| --- | --- | --- | --- |
| `src/CMakeLists.txt` | Links the new isolated Crown consensus sources into existing common build targets. | Build wiring only | Low |
| `src/test/CMakeLists.txt` | Registers the new Crown consensus unit-test file with `test_bitcoin`. | Test build wiring only | Low |

## Files intentionally left untouched in Phase 2

- `src/validation.cpp`
- `src/net_processing.cpp`
- chainstate
- mempool
- miner
- wallet
- script validation
- fork-choice logic

## Merge-risk summary

Phase 2 introduces no meaningful new upstream consensus-coupled surface. The only upstream edits are localized build/test registration changes, so rebasing risk should remain low relative to the larger Phase 1 chain-selection and startup plumbing already present.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ add_library(bitcoin_common STATIC EXCLUDE_FROM_ALL
common/url.cpp
compressor.cpp
core_io.cpp
crown/consensus/engine.cpp
crown/consensus/types.cpp
crown/options.cpp
crown/validator.cpp
deploymentinfo.cpp
Expand Down
Loading