mirror of
https://github.com/luxfi/proofs.git
synced 2026-10-30 15:21:05 +00:00
Add the store-presence-fixed-point theorem (a node holding gossiped-but-unaccepted blocks reports caught-up at its stale height forever), the acceptance-converges theorem (cert-gated accept of held blocks reaches the frontier), and the frozen-cache lemma (recognition must read the advancing finalised ledger, not the plugin LastAccepted cache). Proven on mainnet luxd-2 (1082780 -> 1082796). Co-authored-by: Hanzo Dev <[email protected]>
320 lines
18 KiB
TeX
320 lines
18 KiB
TeX
%% ===================================================================
|
|
%% Bootstrap recovery: liveness under validator loss + finality safety
|
|
%% Companion proof to LP-304 (Bootstrap Trust Anchor — weak-subjective
|
|
%% recovery decoupled from consensus finality).
|
|
%%
|
|
%% Establishes:
|
|
%% (Thm 1) the prior model (bootstrap gated on >2/3 of CURRENT stake)
|
|
%% is UNSATISFIABLE for mass recovery: there is a reachable
|
|
%% system state from which no node can ever bootstrap.
|
|
%% (Thm 2) the LP-304 BootstrapTrust policy is LIVE: a node converges
|
|
%% whenever an honest configured-beacon supermajority is
|
|
%% reachable, EVEN with > 1/3 of validators down.
|
|
%% (Thm 3) the decoupling preserves FINALITY SAFETY: no block is
|
|
%% finalized except by > 2/3 of current validator stake; the
|
|
%% bootstrap anchor never finalizes (C1 preserved).
|
|
%% ===================================================================
|
|
|
|
\documentclass[11pt]{article}
|
|
\usepackage{amsmath,amssymb,amsthm}
|
|
\usepackage{booktabs}
|
|
\usepackage{enumitem}
|
|
\usepackage{hyperref}
|
|
\usepackage[margin=1in]{geometry}
|
|
|
|
\hypersetup{colorlinks=true,linkcolor=black,citecolor=blue,urlcolor=blue}
|
|
|
|
\newtheorem{theorem}{Theorem}
|
|
\newtheorem{lemma}[theorem]{Lemma}
|
|
\newtheorem{corollary}[theorem]{Corollary}
|
|
\newtheorem{definition}{Definition}
|
|
\newtheorem{proposition}[theorem]{Proposition}
|
|
\newtheorem{remark}{Remark}
|
|
|
|
\title{Bootstrap Recovery Liveness under Validator Loss,\\
|
|
with Preserved Consensus-Finality Safety}
|
|
\author{Lux Industries --- Consensus Group \\ Companion proof to LP-304}
|
|
\date{2026-06-27}
|
|
|
|
\begin{document}
|
|
\maketitle
|
|
|
|
\begin{abstract}
|
|
We formalise the separation, introduced in LP-304, of the \emph{bootstrap trust} threshold
|
|
from the \emph{consensus finality} threshold. We model a primary network of weighted
|
|
validators a subset of which may be offline, including the very nodes attempting to recover.
|
|
We prove (i) the prior design, which named the bootstrap frontier by a quorum over
|
|
$>\!\tfrac23$ of \emph{current total stake}, has a reachable deadlock state in which no node
|
|
can bootstrap; (ii) the LP-304 policy, naming the frontier from an authenticated
|
|
configured-beacon supermajority with a response floor, is live whenever an honest
|
|
configured-beacon supermajority is reachable, even with more than $\tfrac13$ of validators
|
|
offline; and (iii) the two-threshold decoupling preserves BFT finality safety: a block is
|
|
accepted only under $>\!\tfrac23$ of \emph{current} validator stake, and the bootstrap anchor
|
|
never finalises. The third result is the weak-subjectivity soundness condition (``C1'')
|
|
under which the liveness gain costs no safety.
|
|
\end{abstract}
|
|
|
|
\section{Model}
|
|
|
|
\begin{definition}[Validator set and stake]
|
|
Let $V=\{v_1,\dots,v_n\}$ be the current primary-network validators with stake weights
|
|
$w:V\to\mathbb{Z}_{>0}$ and total $W=\sum_{v\in V}w(v)$. The two-thirds floor is
|
|
$\mathsf{F}(W)=\lfloor 2W/3\rfloor$; a stake mass $s$ \emph{clears} the floor iff $s>\mathsf{F}(W)$.
|
|
\end{definition}
|
|
|
|
\begin{definition}[Reachability]
|
|
At a point in time a subset $R\subseteq V$ is \emph{reachable} (connected and responding). A
|
|
node $u$ attempting to recover is itself offline-for-recovery: $u\notin R$. Write
|
|
$W_R=\sum_{v\in R}w(v)$ for the reachable stake.
|
|
\end{definition}
|
|
|
|
\begin{definition}[Configured beacon anchor]
|
|
Independent of $V$, each node holds a \emph{configured beacon set} $B$ resolved, in priority
|
|
order, from (1) operator configuration, (2) a trusted finalized checkpoint, or (3) genesis.
|
|
$B$ is fixed at the node and \textbf{not} derived from peer self-report. Let $B_R=B\cap R$ be
|
|
the reachable beacons and $\mathsf{honest}(B_R)\subseteq B_R$ the honest ones.
|
|
\end{definition}
|
|
|
|
\begin{definition}[Bootstrap policy, LP-304]\label{def:policy}
|
|
A $\mathsf{BootstrapPolicy}$ is $(\,B,\ \rho,\ m,\ \mathsf{cp}\,)$ with agreement ratio
|
|
$\rho\in\{\tfrac23,\tfrac34\}$, response floor $m\in\mathbb{Z}_{\ge 2}$, and optional
|
|
checkpoint $\mathsf{cp}$. On authenticated replies from responders $B_R$, it
|
|
\textbf{accepts} a frontier block $b$ iff
|
|
\[
|
|
|B_R|\ \ge\ m \quad\text{and}\quad w\!\left(\{\,v\in B_R : b \preceq \mathsf{tip}(v)\,\}\right)\ >\ \rho\cdot W_{B_R},
|
|
\]
|
|
where $b\preceq \mathsf{tip}(v)$ means $b$ is the reported tip of $v$ or an ancestor of it
|
|
(ancestor-tolerant naming, LP-304 \S algorithm), and $W_{B_R}=\sum_{v\in B_R}w(v)$ is the
|
|
\emph{responding} beacon weight; or $\mathsf{cp}$ explicitly authorises $b$. The denominator
|
|
is the responding beacons, never $W$.
|
|
\end{definition}
|
|
|
|
\section{Unsatisfiability of the prior (current-stake) bootstrap threshold}
|
|
|
|
\begin{definition}[Prior threshold]
|
|
The prior design names a frontier only if the stake of validators agreeing on it clears
|
|
$\mathsf{F}(W)$ over the \emph{current total} $W$.
|
|
\end{definition}
|
|
|
|
\begin{theorem}[Mass-recovery deadlock]\label{thm:deadlock}
|
|
There is a reachable state in which the prior threshold can never be met, hence no offline
|
|
node bootstraps, even though the network is otherwise correct.
|
|
\end{theorem}
|
|
|
|
\begin{proof}
|
|
Take $n=5$, $w\equiv c$, so $W=5c$ and $\mathsf{F}(W)=\lfloor 10c/3\rfloor=3c$ (for $c$ a
|
|
multiple of $3$, and $3c<10c/3$ so the strict floor is $3c$). Let two validators be offline
|
|
for recovery, $R=\{v_1,v_3,v_4\}$, $W_R=3c$. The maximum stake that can agree on any frontier
|
|
is $W_R=3c$, and $3c \not> 3c$. The floor is never cleared, independent of agreement quality
|
|
or ancestor tolerance. The two offline validators contribute the missing $2c$; but they are
|
|
exactly the nodes whose recovery is blocked. The blocked set and the missing stake coincide,
|
|
so the state is a fixed point: recovery requires their stake, their stake requires their
|
|
recovery. $\qed$
|
|
\end{proof}
|
|
|
|
\begin{remark}
|
|
Theorem~\ref{thm:deadlock} is not an eclipse or a fault: $R$ is honest and reachable. It is a
|
|
threshold-model error --- the \emph{finality} denominator $W$ used for a \emph{liveness}
|
|
(bootstrap) decision. This is precisely the mainnet state observed for \texttt{luxd-2}
|
|
(LP-304, \S empirical): $W=2.5\times10^{18}$, $\mathsf{F}=1.\overline{6}\times10^{18}$,
|
|
$W_R=1.5\times10^{18}=60\%<66.\overline{6}\%$.
|
|
\end{remark}
|
|
|
|
\section{Liveness of the LP-304 policy}
|
|
|
|
\begin{theorem}[Recovery liveness under validator loss]\label{thm:liveness}
|
|
Let the policy be $(B,\rho,m,\cdot)$ with $\rho\le\tfrac34$. Suppose the reachable honest
|
|
beacons satisfy $|B_R|\ge m$ and $w(\mathsf{honest}(B_R))>\rho\cdot W_{B_R}$, and the honest
|
|
beacons agree (tip-or-ancestor) on a common block $b^\star$. Then the policy accepts a
|
|
frontier $b\succeq$ the honest-agreed height and the node syncs to it --- even if
|
|
$W_R\le \mathsf{F}(W)$, i.e.\ more than $\tfrac13$ of \emph{total} validators are offline.
|
|
\end{theorem}
|
|
|
|
\begin{proof}
|
|
The honest beacons all have $b^\star\preceq\mathsf{tip}(\cdot)$, so the agreeing weight on
|
|
$b^\star$ is at least $w(\mathsf{honest}(B_R))>\rho\,W_{B_R}$, clearing the policy's
|
|
\emph{responding-beacon} threshold; and $|B_R|\ge m$ clears the floor. By
|
|
Definition~\ref{def:policy} the policy accepts $b^\star$ (or a higher block on the same chain
|
|
with the same property; ancestor tolerance selects the highest such). Acceptance depends only
|
|
on $W_{B_R}$ and $|B_R|$, never on $W$; the offline validators' absence from $B_R$ does not
|
|
enter. Hence acceptance holds for any amount of offline \emph{total} stake, including
|
|
$W_R\le\mathsf{F}(W)$, as long as the honest reachable-beacon supermajority condition holds.
|
|
For the $n=5$, $R=\{v_1,v_3,v_4\}$ instance with $B=V$, $m=3$, $\rho=\tfrac23$: $|B_R|=3\ge 3$
|
|
and (all three honest) the agreeing weight $3c>\tfrac23\cdot 3c=2c$, so $b^\star=1082796$ is
|
|
accepted --- the case Theorem~\ref{thm:deadlock} deadlocks. $\qed$
|
|
\end{proof}
|
|
|
|
\begin{proposition}[Anti partition-capture]\label{prop:floor}
|
|
With $m\ge 2$ and the strict ratio $\rho$, an attacker who partitions the node to
|
|
$|B_R|<m$ reachable beacons cannot make the policy accept any frontier, regardless of their
|
|
unanimity.
|
|
\end{proposition}
|
|
|
|
\begin{proof}
|
|
Acceptance requires $|B_R|\ge m$. If $|B_R|<m$ the first conjunct of
|
|
Definition~\ref{def:policy} fails outright; unanimity ($\rho\,W_{B_R}$ trivially cleared)
|
|
is irrelevant. Only an explicit operator checkpoint $\mathsf{cp}$ can authorise a frontier
|
|
below the floor, by deliberate operator action. $\qed$
|
|
\end{proof}
|
|
|
|
\section{Finality safety is preserved (weak-subjectivity soundness, ``C1'')}
|
|
|
|
\begin{definition}[Finality]
|
|
A block is \emph{final} iff it carries a verified $\alpha$-of-$K$ quorum certificate whose
|
|
signing weight clears $\mathsf{F}(W)$ over the \emph{current} validator stake (LP-045/142).
|
|
$\mathsf{HasFinality}(s,W)\equiv s>\mathsf{F}(W)$.
|
|
\end{definition}
|
|
|
|
\begin{theorem}[Decoupling preserves safety]\label{thm:safety}
|
|
The LP-304 separation does not change the finality predicate: a block is accepted as final
|
|
iff $\mathsf{HasFinality}$ holds on current stake. The bootstrap policy never finalises a
|
|
block, and no frontier it names is treated as final.
|
|
\end{theorem}
|
|
|
|
\begin{proof}
|
|
$\mathsf{BootstrapTrust.AcceptsFrontier}$ returns a value of type $\mathsf{Frontier}$ (a sync
|
|
target), never a certificate, and the descent re-executes and re-verifies every block before
|
|
the node re-enters consensus (Invariant~3); after re-entry, acceptance is dispatched solely
|
|
through $\mathsf{ConsensusQuorum.HasFinality}$ on the current stake set, syntactically distinct
|
|
from $\mathsf{BootstrapTrust}$. The two interfaces share no implementation: the policy's
|
|
denominator is responding-beacon weight $W_{B_R}$, the finality denominator is current stake
|
|
$W$. Therefore for any block $b$ marked final there is a certificate with weight $>\mathsf{F}(W)$;
|
|
the bootstrap path produces no such certificate and cannot mark $b$ final. $\qed$
|
|
\end{proof}
|
|
|
|
\begin{theorem}[Weak-subjective soundness of the named frontier]\label{thm:c1}
|
|
Under the assumption that the configured beacon set contains less than a $\rho$-fraction of
|
|
Byzantine responding weight, the policy never names a forged (non-canonical) frontier.
|
|
\end{theorem}
|
|
|
|
\begin{proof}
|
|
A forged block $f$ is on $\mathsf{tip}(v)$'s chain only for Byzantine $v$ (an honest beacon
|
|
reports its real accepted chain, and the ancestor relation $f\preceq\mathsf{tip}(v)$ is
|
|
content-addressed: $f$'s id is the hash of its bytes, and the descent follows verified
|
|
$\mathsf{parent}$ links, so a substituted parent yields a different id and is unreachable ---
|
|
LP-304 \S rationale). Hence the agreeing weight on $f$ is at most the Byzantine responding
|
|
weight $<\rho\,W_{B_R}$, which does not clear the policy threshold; $f$ is never named (tests
|
|
D, E). The canonical block, backed by the honest $>\rho$ supermajority, is named instead.
|
|
An attacker cannot enlarge the Byzantine fraction by injecting beacons, since $B$ is resolved
|
|
from configuration/checkpoint/genesis and a non-configured peer has zero weight
|
|
(Invariant~1, test~D). $\qed$
|
|
\end{proof}
|
|
|
|
\section{Caught-up by acceptance, not store presence}
|
|
|
|
The policy of \S\ref{def:policy} names the correct frontier $b^\star$, but a node only
|
|
\emph{converges} if it then \emph{recognises} that it has reached $b^\star$ and otherwise
|
|
advances toward it. Two further degrees of freedom in that recognition --- which set of blocks
|
|
counts as ``reached,'' and which height the loop reads to detect advancement --- admit a
|
|
non-converging fixed point that named-frontier correctness alone does not exclude. This was the
|
|
final live-mainnet defect (LP-304, layer 8).
|
|
|
|
\begin{definition}[Held vs.\ accepted]
|
|
A recovering node $u$ has two monotone heights: its \emph{accepted height} $\mathsf{acc}(u)$ (the
|
|
top of its consensus-accepted chain) and its \emph{held height} $\mathsf{held}(u)\ge\mathsf{acc}(u)$
|
|
(the highest block present in its block store). Block gossip may raise $\mathsf{held}(u)$ above
|
|
$\mathsf{acc}(u)$: the node \emph{has} blocks it has not \emph{accepted}. Let $N^\star$ be the named
|
|
frontier height (Thm~\ref{thm:liveness}), with $N^\star>\mathsf{acc}(u)$.
|
|
\end{definition}
|
|
|
|
\begin{definition}[Caught-up predicates]
|
|
The \emph{store-presence} predicate is
|
|
$\mathsf{CU}_{\mathsf{Has}}(u)\equiv \mathsf{held}(u)\ge N^\star$ (the named tip is present in the
|
|
store). The \emph{acceptance} predicate is
|
|
$\mathsf{CU}_{\mathsf{Acc}}(u)\equiv \mathsf{acc}(u)\ge N^\star$ (the named tip is on the accepted
|
|
chain). When caught-up is false, the loop runs one \emph{cert-gated accept step}: it accepts the
|
|
held block at height $\mathsf{acc}(u)+1$ iff that block carries a verifying $\alpha$-of-$K$
|
|
certificate, raising $\mathsf{acc}(u)$ by one; with no caught-up signal it instead concludes and
|
|
goes live.
|
|
\end{definition}
|
|
|
|
\begin{theorem}[Store-presence caught-up is a non-converging fixed point]\label{thm:has}
|
|
There is a reachable state with $\mathsf{held}(u)\ge N^\star>\mathsf{acc}(u)$ in which
|
|
$\mathsf{CU}_{\mathsf{Has}}(u)$ holds, so the loop concludes ``caught up'' and runs no accept step,
|
|
yet $u$ is not at the frontier. The state is a fixed point: $\mathsf{acc}(u)$ never advances, and
|
|
every restart re-enters it.
|
|
\end{theorem}
|
|
|
|
\begin{proof}
|
|
Let $u$ have accepted to $\mathsf{acc}(u)=h_0$ and received by gossip every block up to
|
|
$N^\star=h_0+k$, so $\mathsf{held}(u)=h_0+k\ge N^\star$. Then
|
|
$\mathsf{CU}_{\mathsf{Has}}(u)=(\mathsf{held}(u)\ge N^\star)=\text{true}$, so the loop takes the
|
|
caught-up branch and performs no accept step; $\mathsf{acc}(u)$ stays $h_0<N^\star$. Nothing in the
|
|
branch mutates $\mathsf{held}$ or $\mathsf{acc}$, so the state is fixed. On restart the store still
|
|
holds the blocks, $\mathsf{CU}_{\mathsf{Has}}$ is again true, and the same branch is taken --- the
|
|
defect is self-reinforcing. The node serves a stale accepted chain while believing it is current.
|
|
$\qed$
|
|
\end{proof}
|
|
|
|
\begin{remark}
|
|
This is exactly the observed mainnet state: \texttt{luxd-2} logged
|
|
\texttt{NAMED namedHeight=1082796 held=true} with $\mathsf{acc}=1082780$ --- it \emph{held}
|
|
$1082781..1082796$ by gossip but had \emph{accepted} only to $1082780$, and the store-presence
|
|
predicate (resolving ``held'' through the VM's \texttt{GetBlock}, which returns stored \emph{or}
|
|
accepted blocks alike) reported caught-up at the stale height (LP-304, layer 8).
|
|
\end{remark}
|
|
|
|
\begin{theorem}[Acceptance caught-up converges, safely]\label{thm:acc}
|
|
Using $\mathsf{CU}_{\mathsf{Acc}}$, a node with $\mathsf{held}(u)\ge N^\star>\mathsf{acc}(u)$ and a
|
|
valid certificate for each held block on the named chain reaches $\mathsf{acc}(u)=N^\star$ in
|
|
exactly $N^\star-\mathsf{acc}(u)$ accept steps, and no block is accepted without its certificate.
|
|
\end{theorem}
|
|
|
|
\begin{proof}
|
|
While $\mathsf{acc}(u)<N^\star$, $\mathsf{CU}_{\mathsf{Acc}}(u)$ is false, so the loop runs an
|
|
accept step. The block at height $\mathsf{acc}(u)+1$ is present (since
|
|
$\mathsf{held}(u)\ge N^\star>\mathsf{acc}(u)+1$ until the last step) and carries a verifying
|
|
certificate by hypothesis, so the cert-gated guard accepts it and $\mathsf{acc}(u)$ increases by
|
|
exactly one. The accept step strictly increases a quantity bounded above by $N^\star$, so after
|
|
$N^\star-\mathsf{acc}_0$ steps $\mathsf{acc}(u)=N^\star$ and $\mathsf{CU}_{\mathsf{Acc}}$ becomes
|
|
true. Safety: the guard accepts a block \emph{only} on a verifying $\alpha$-of-$K$ certificate, so a
|
|
stored block lacking one (a forged or off-chain block in the store) is never accepted merely for
|
|
being present --- store presence confers no acceptance. $\qed$
|
|
\end{proof}
|
|
|
|
\begin{lemma}[Convergence recognition must read the advancing ledger]\label{lem:frozen}
|
|
Suppose the accept step advances the in-process finalised height $\mathsf{acc}(u)$, but the loop
|
|
evaluates caught-up against a cached value $\widehat{\mathsf{acc}}(u)$ that is written once at
|
|
initialisation and never refreshed. Then even under $\mathsf{CU}_{\mathsf{Acc}}$ the node fails to
|
|
recognise convergence: it advances on disk yet loops forever. Reading $\mathsf{acc}(u)$ from the
|
|
finalised ledger restores Thm~\ref{thm:acc}.
|
|
\end{lemma}
|
|
\begin{proof}
|
|
$\mathsf{CU}_{\mathsf{Acc}}$ evaluated on the frozen cache is
|
|
$\widehat{\mathsf{acc}}(u)\ge N^\star$, with $\widehat{\mathsf{acc}}(u)=\mathsf{acc}_0<N^\star$
|
|
constant. It is false at every step regardless of the real $\mathsf{acc}(u)$; the loop keeps running
|
|
accept steps (or, past the top, finds nothing to accept and stalls) and never reports caught-up ---
|
|
an advance-then-stall. Substituting the live finalised height $\mathsf{acc}(u)$ for
|
|
$\widehat{\mathsf{acc}}(u)$ makes the predicate the one of Thm~\ref{thm:acc}, which converges. $\qed$
|
|
\end{proof}
|
|
|
|
\begin{remark}
|
|
The frozen cache is the plugin (zap) RPC client's \texttt{LastAccepted}, written at
|
|
initialisation and not on \texttt{Accept}; the live source is the consensus finalised ledger that
|
|
the per-height accept guard already maintains. Driving recognition off the ledger (and refreshing
|
|
the client cache on \texttt{Accept}, since the stale value was also served to peers) is the layer-8
|
|
fix. The unit mocks hid both Thm~\ref{thm:has} and Lemma~\ref{lem:frozen} because the mock VM
|
|
advanced \texttt{LastAccepted} on accept and resolved ``held'' as ``accepted'' --- it was
|
|
\emph{higher-fidelity} than the real host in exactly the two ways that mask the bug, so a green
|
|
suite did not imply convergence.
|
|
\end{remark}
|
|
|
|
\section{Conclusion}
|
|
|
|
\begin{corollary}
|
|
Separating $\mathsf{BootstrapTrust}$ from $\mathsf{ConsensusQuorum}$ converts an
|
|
unsatisfiable recovery (Thm~\ref{thm:deadlock}) into a live one under realistic validator
|
|
loss (Thm~\ref{thm:liveness}, Prop~\ref{prop:floor}) at no cost to finality safety
|
|
(Thm~\ref{thm:safety}) and no new forgery surface under the standard weak-subjectivity
|
|
assumption (Thm~\ref{thm:c1}). Convergence is then \emph{recognised} correctly only when
|
|
caught-up is defined by acceptance, not store presence (Thm~\ref{thm:has},
|
|
Thm~\ref{thm:acc}), and is read from the advancing finalised ledger, not a frozen cache
|
|
(Lemma~\ref{lem:frozen}); both are cert-gated, so safety is preserved. Validators may freely
|
|
leave and rejoin: a rejoining node bootstraps from whichever configured beacons are reachable
|
|
and agreeing, accepts the gap under quorum certificates, and finalises on the current stake set.
|
|
The liveness threshold and the safety threshold are distinct objects with distinct denominators,
|
|
and ``reached the frontier'' is the accepted chain, never the store --- none can be re-conflated.
|
|
\end{corollary}
|
|
|
|
\end{document}
|