CAIN-42 MCPGate

CAIN-42 Byzantine-replica tests across three regions

Byzantine-replica tests across the three regions of the CAIN-42 deployment (Atlanta, Los Angeles ×2, Miami) on the production image. The live production cluster refuses fault injection by design, so the tests ran on a separate, disposable 4-replica cluster with the same placement, removed afterwards. This page loads every quorum certificate the three honest replicas hold, and your browser re-checks them.

What happened

B1: a replica forging votes (cain-byz-node-3). It sent COMMIT votes claiming to come from another member, signed with its own key. Every honest replica rejected them (cain-byz-node-1: 6, cain-byz-node-2: 6, cain-byz-node-4: 6 rejected), and 6/6 writes committed: PASS.

B2: an equivocating primary (cain-byz-node-1). The leader sent two conflicting, correctly signed proposals for one sequence. All three honest replicas built an equivocation proof from the leader's own two signatures and quarantined it (cain-byz-node-2, cain-byz-node-3, cain-byz-node-4). The view changed 0 to 1, and 6/6 writes committed under the new primary: PASS.

The equivocation proof is in the bundle. verify_byzantine_bundle.py checks that both conflicting proposals carry the accused replica's own valid signature, so the accusation needs no trust in the accusers.

Verify (about 5 seconds)

What is checked

  1. The membership configuration hash is recomputed from the 4 member ids and Ed25519 public keys. Every node and every certificate must carry it.
  2. For every sequence on every node, the COMMIT_QC and the PREPARE_QC. Each vote must be an Ed25519 signature by a distinct member over SHA-256 of the canonical signed message. It must have the right type (a COMMIT vote never counts as a PREPARE vote) and match this cluster, epoch, view, sequence and digest. Each certificate needs at least 3 distinct signers. The leader's proposal must be signed by the primary of that view, and its digest must bind the proposed operation.
  3. The certificate hash and signature-bundle hash are recomputed from the content.
  4. Evolution 3 fast path: a FAST_COMMIT_QC (a decision taken without the COMMIT round) is accepted only if the published membership declares the fast path and all four members signed it. Three of four is never enough for a fast commit.
  5. The decision chain is folded from genesis: decision_hash(seq) = H(cluster, epoch, seq, digest, parent). It must be contiguous and identical on all four nodes, and the nodes must end with the same application-state hash.
  6. View-change quorum certificates, and one consensus-to-enforcement AuthorizationCertificate per node.
  7. Negative controls: a certificate is tampered with in seven ways, and every tampered copy must be rejected.

The same checks, without a browser: curl -so verify_pbft_qc_bundle.py verify_pbft_qc_bundle.py.txt && python3 verify_pbft_qc_bundle.py PBFT_QC_BUNDLE.json (needs pip install cryptography, no CAIN code).