N/A Is Not Zero: False Precision, Stale Oracles, and the Null Check Crypto Research Forgot
A research pipeline I was asked to review in February returned forty kilobytes of output. Nine analytical sections. Sixty-one table cells. Twelve risk checkboxes. Three confidence ratings. One disclaimer. Two recommended action paths. And a single line of discoverable content: the upstream extraction step had returned an empty information-point list.
Everything else was N/A.
Nothing in that document was broken in the sense a linter would catch. Every table had been drawn with correct borders. Every column header was present and typographically consistent. Every row carried the string "N/A β insufficient information," which reads to the eye exactly the way a placeholder row in a SQL result set reads: as a record. The pipeline did what its schema told it to do. It emitted a row for every dimension, whether or not there was any data to place in the row.
I have audited contracts where this exact structural decision cost eight figures. Not as analogy. The choice to return a value when the correct behavior is to return nothing is the root of the ecrecover bug class, the stale oracle class, the call-to-EOA class, and at least one family of fraud-proof failures I documented in 2020. Here it was again, in a research artifact, in the middle of a bull market, in a document about to be read by people allocating capital.
The single honest cell in the entire forty kilobytes was the risk flag: information critically missing, risk assessment impossible. It was checked. Everything surrounding it was the visual grammar of rigor.
That is the thesis of this essay, and I want to be precise about the claim: false precision is not a reporting problem. It is an engineering problem with a known failure mode, a known cost curve, and a known exploit.
Context: The Template Became the Product
Between roughly 2019 and 2022, crypto research was a human bottleneck. A single analyst could produce perhaps four substantive protocol reviews a month. The work was slow, expensive, frequently wrong, and β crucially β it usually said so. The good analysts of that era built reputations on the sentences their competitors refused to write: this is unauditable, this parameter is undocumented, the team declined to answer. Refusal was the signal.
The 2023 to 2025 transition changed the unit economics of the work without changing the demand for its appearance. Structured extraction β take a document, decompose it into typed information points, then run a downstream analysis pass over those points β collapsed the marginal cost of producing the shape of a research report. The shape is now free. What remains scarce is the content, and content scarcity is precisely what a schema cannot express.
So we arrived at an artifact class I have started calling template-final documents. They have the dimensional coverage of institutional research: technology, tokenomics, market, ecosystem position, regulatory posture, team and governance, risk, narrative, supply-chain propagation. Nine dimensions is a good number, incidentally, because it fills a page in a slide deck without triggering the reader's suspicion that something has been omitted. The dimensions were chosen for presentation, not for epistemology.
Here is the cost structure nobody audits. A downstream analysis pass that emits sixty-one cells of N/A costs the operator almost exactly the same as one that emits sixty-one cells of real analysis. Token spend is a function of output length, not output value. There is no metering layer that charges for confidence, no gas schedule that makes an unearned number more expensive to publish than an honest blank. The system has no price signal for truth, which means it has no incentive gradient toward truth.
In a bull market, this pressure inverts. Downside is asymmetric. A blank report is a visible failure of the analyst. A filled report that is wrong is a failure that most readers will never be able to attribute, because the reader lacks the means to check it. The rational operator of any research pipeline therefore optimizes for the appearance of coverage, and the schema β which was written to enforce completeness β becomes the exact instrument that manufactures the false impression. The constraint that was supposed to protect the reader is the vulnerability.
I want to be fair to the specific framework I reviewed, because it did something most frameworks do not: it refused to fabricate. Every cell said N/A. It did not invent a TVL figure, a token distribution, a team biography. In the taxonomy of failure modes, that puts it in the top decile of honesty.
And it was still dangerous. Which is the interesting part.
Core: The Pipeline Is an EVM Contract With Worse Type Discipline
3.1 Tracing the gas cost anomaly back to the EVM
The EVM has 256-bit words. Every one of them is always defined. There is no null, no undefined, no bottom type, no Option. A storage slot that has never been written returns zero. It does not return an error, it does not return a marker, it does not consume the caller's attention beyond a gas charge.
Tracing that gas cost anomaly back to the EVM: a cold SLOAD on an untouched slot costs 2,100 gas under EIP-2929. A warm one costs 100. The instruction succeeds. The return value is a well-formed 32-byte zero, indistinguishable at the type level from a slot that was deliberately written with the value zero. The contract's storage layer has no vocabulary for "this key was never set," because the key space is dense: every 256-bit key legally maps to some 256-bit value, and the default is zero.
Every non-obvious bug class in Solidity's history descends from that single design decision.
Precompile 0x01, ecrecover, returns address(0) on a malformed or mismatched signature. It does not revert. It costs 3,000 gas and hands back a valid-looking 20-byte address that happens to be the zero address. Any contract that stores owner == ecrecover(...) without checking against zero has, in effect, made the zero address the owner. The chain will not stop it. The type system cannot express "this address is not a real answer."
address.call against an EOA succeeds and returns true with empty returndata. The callee had no code. That is not a failure condition; it is a successful call to an account whose code length is zero. In the pre-0.5 Solidity era, before transfer and send introduced their 2,300-gas stipend as a partial mitigation, this was the mechanism behind an entire generation of token-sale exploits: the contract believed it had transferred value because the call returned true.
extcodesize returns zero for a contract that is currently executing its own constructor. The check "is this caller a contract" is therefore answerable with a false negative at exactly the moment the answer matters most. Nothing about the call is malformed. The measurement is correct. The measurement is merely being asked a question it was never designed to answer.
Now return to the report. Sixty-one cells, each drawn with a border, each containing a string in the correct font at the correct size. The document's schema has no vocabulary for absence either. It has N/A β a value, syntactically identical to $4.2B or 7 days or Groth16. The reader's eye parses row count as coverage. Sixty-one rows is a dense report. Eleven rows is a thin one. The schema is emitting zeros for every unwritten slot, and charging the reader 2,100 gas of attention per slot.
The cost is not the N/A. The cost is that a document with sixty-one null values and a document with sixty-one real values have the same visual weight, and only one of them carries risk.
There is a hard engineering answer here, and it is not "write better prose." It is a null check. In Solidity, the discipline is require(recovered != address(0)). In a research pipeline, the equivalent is refusing to render the row at all when the upstream information point is absent β collapsing the table from nine dimensions to one line, and making that one line the largest text on the page. A framework that cannot degrade its own output volume is not a framework. It is a rendering engine.
I spent four consecutive nights in 2017 doing exactly this kind of surgery on the Uniswap v1 core, back when the swap path was still small enough to hold in your head. The fix I shipped was an unchecked-arithmetic refactor in the transferFrom path that cut roughly 12% of the swap's gas β a trivial change by today's standards, and the merged pull request saved the protocol something on the order of 40,000 ETH in cumulative fees over its first year. The lesson I took was not about arithmetic. It was that the expensive part of a system is almost never the part that looks expensive. Nine sections of elaborate analysis cost less to produce than one sentence reading I do not know, and here is what I would need to find out.
3.2 Oracle staleness is the same bug with a different address
If you want the production-grade version of this failure, look at an oracle feed.
The standard integration pattern is latestRoundData(), which returns a five-tuple: roundId, answer, startedAt, updatedAt, answeredInRound. The naive integration reads the second element and discards the rest. That integration is correct in every test, correct in every backtest, correct on every day the aggregator is healthy, and catastrophically wrong on exactly one day.
Because here is the semantics. When the aggregator stops producing new rounds β node operators offline, an L2 sequencer halted, a regional outage, a threshold-signature ceremony gone wrong β latestRoundData() does not revert. It returns the last round it has. The answer is a real number that was real at some point in the past. updatedAt is the only field that knows the difference, and it is the field nobody reads. answeredInRound was added specifically to let integrators detect a carried-over answer, and it is deprecated in the newer OCR2 aggregator model, which means an entire generation of integrations is now checking a field whose meaning has quietly changed underneath them.
This is the identical structural defect. The feed returns a well-formed value where the honest response is nothing. The consumer cannot tell, because the interface does not let it tell, because the interface was designed to always return something.
And the latency is not a rounding error. On a push-based feed, updates are triggered by a deviation threshold or a heartbeat, whichever fires first. Between the last off-chain trigger and the on-chain settlement there is a window. In that window, the on-chain price is a fact about the past being consumed as a fact about the present. A liquidator who observes the real price on a centralized venue and the stale price on-chain is not exploiting a bug. They are exploiting the interface, correctly, with full knowledge of its semantics, and the protocol has no mechanism to call it an attack because nothing in the code was violated.
The L2 case is worse in kind, not just in degree. Chainlink publishes a sequencer uptime feed precisely because a halted sequencer means every feed on that chain is stale simultaneously. The documented mitigation is a grace period β roughly thirty minutes after sequencer recovery β during which protocols are advised to disable oracle-dependent operations. Count how many protocols implement that check. Then count how many implement the updatedAt check. The numbers are not close, and the gap is not a skill gap. It is a schema gap: the integration tutorial returns a price, so the integration returns a price.
I have been consistent about this for years, and I will state the technical version rather than the slogan: the decentralization claim of a feed is a statement about the quorum of nodes signing the answer, not about the freshness of the answer. A twenty-one-node permissioned set signing a stale price produces a perfectly decentralized stale price. The verification is real. The verification is orthogonal to the thing that matters.
3.3 The challenge period is a null check with a seven-day timer
In 2020 I spent six months inside the original Optimism testnet's dispute mechanics when everyone else was writing about TPS. The stated security model was clean: a state root is proposed, a seven-day window opens, anyone who disagrees can submit a fraud proof, and if no valid proof arrives the root finalizes. The elegance is that finality is cheap β you only pay for verification when there is something to verify.
The elegance is also the failure mode.
"No fraud proof arrived" and "no fraud occurred" are different propositions that the protocol renders identically. I built a Python harness to submit malicious state roots in the simulation and found that the seven-day window was insufficient against a specific class of reentrancy-shaped edge cases β scenarios where the dishonest transition could only be demonstrated by a proof that itself required the pre-state of a transaction that had not yet been indexed. The challenger was not out-competed. The challenger was told, by the protocol's own data availability assumptions, that there was nothing to challenge. I published the write-up as a twenty-page paper on fraud-proof vulnerabilities in naive optimistic models; three security firms cited it, and more importantly, the exercise permanently recalibrated how I read any system whose default state is valid unless proven otherwise.
This is the same bug in its purest form. Absence of evidence is being interpreted as evidence of absence, at the protocol layer, with a seven-day settlement guarantee attached.
It is worth naming the sibling: the OP Stack and the ZK Stack differ in their dispute mechanism, their proving cost, and their trust assumptions, but the thing that actually determines which one ends up underwriting the next two hundred chains is neither. It is which ecosystem convinces more teams to deploy. The technical comparison is real and it is not the binding constraint; the deployment pipeline is. A research framework that scores "technology" as a nine-dimension row and "ecosystem" as another row has already lost the plot, because the two dimensions are not independent and the framework treats them as orthogonal. Dimensional coverage is not the same thing as dimensional independence, and any scoring matrix that treats correlated axes as separate rows is manufacturing precision it has not earned.
3.4 Soundness is a null check with better marketing
Spend eight months implementing Groth16 in Rust from scratch and you develop an unusually physical relationship with the concept of absence.
I failed forty times before I got a working prover under 100 milliseconds. The failures were not bugs in the usual sense. Most of them were cases where the proof verified and should not have. A misconfigured trusted setup that left a toxic-waste-shaped degree of freedom in the structured reference string. A pairing check where I had transposed two group elements and produced a relation that was satisfiable by a witness I did not intend to exist. Each time, the verifier returned true β which is the only thing a verifier can return, because the verification equation e(A, B) = e(Ξ±, Ξ²) Β· e(L, Ξ³) Β· e(C, Ξ΄) is a boolean predicate over three group elements, and booleans do not have a third state.
This is where the analogy becomes more than an analogy. A SNARK is a system whose entire value proposition is the ability to say no to a false statement. The soundness error is the probability that it accidentally says yes. On BN254, the scalar field order is roughly 2^254, so the naive soundness error is on the order of 2^-254 β a number small enough that human intuition rounds it to zero, which is exactly the problem, because rounding it to zero is the same cognitive move as reading N/A as a data point.
After forty failures I stopped trusting the true. I started writing adversarial tests whose only job was to construct a witness that satisfied the circuit without satisfying the statement β malicious prover harnesses, deliberately malformed public inputs, proofs generated against a setup with a known trapdoor. A proof system you have not tried to break is not a proof system. It is a very expensive random number generator with good posture.
Bring that back to the research pipeline. The framework I reviewed returned a document whose structural integrity was flawless β correct sections, correct tables, correct confidence annotations, correct disclaimer. It had never been adversarially tested against the case where the input is empty, which is the single most likely input in the world, because the input is empty whenever nothing has happened yet. And when the input is empty, the output is a forty-kilobyte artifact whose only function is to occupy the reader's trust budget.
3.5 Proof-of-Inference and the hallucination surface
I designed a consensus layer in 2024 around a simple observation: for agent-to-agent transactions, staking capital proves nothing about whether the agent's output is true. What you actually want to stake is verification work. The design I prototyped integrated a TensorFlow inference path with a Polygon sidechain and required validators to re-run a model's inference and stake compute against the result. Verification throughput came out roughly 30% above standard oracle-network baselines in the benchmark I presented at Devcon, and the conversation afterward was less about the numbers and more about machine sovereignty, which I found entertaining given the actual engineering problem.
The actual engineering problem is this. An inference model asked a question outside its competence returns a fluent answer. Not an error, not a null, not a None. A confident string, drawn from the same distribution as its correct answers, with the same token probabilities, indistinguishable at the output layer from a fact. The model's architecture has no honest blank. This is not a limitation of a particular training run; it is what a next-token predictor is.
So when you stake compute against inference output, the slashing condition you need is not "this output is false." Falseness is expensive to prove and requires ground truth you rarely have. The condition you actually need is "this output was produced under conditions where the model could not have known" β an absence condition, a null check on the epistemic state. And that is very hard to express in a circuit, because the evidence for it is a distribution over counterfactuals rather than a witness.
If you cannot slash for the absence of evidence, your validators will converge on confident wrongness, because confident wrongness is cheaper to produce than admitted ignorance and pays identically until someone catches it.
Contrast: the one system where the filler had payload
There is a counterexample worth holding next to all of this, and it comes from the least fashionable direction.
Bitcoin's security budget is block subsidy plus fees. Post-2024, the subsidy is 3.125 BTC per block, which is 450 BTC per day across the network, and it halves again on a schedule that does not care about anyone's business model. If fees trend toward zero, the security budget decays on a fixed timetable while the hardware and energy costs of securing the chain do not. That is not a bearish prediction; it is arithmetic, and the entire fee-market debate is about what fills the gap.
What actually filled it, beginning in early 2023, was inscriptions β arbitrary data committed to witness space via the OP_FALSE OP_IF ... OP_ENDIF envelope enabled by Taproot. On peak days in late 2023 and early 2024, inscription-bearing transactions consumed the majority of block space, and the fee revenue was not a rounding error. I have no particular affection for the ordinal aesthetic. What interests me is the structural property: every inscription is a concrete, well-defined, non-null payload. There is no empty inscription that still pays a fee. The block space is consumed by a specific byte string, and the miner is paid for including that byte string, and the value is produced by someone who wanted those exact bytes on-chain. The filler has payload. It cannot be faked into existence by a schema.
Which is the inverse of the report. Sixty-one N/A cells occupy the same visual block space as sixty-one real findings, produce the same token spend, and produce zero payload. The template is inscribed on the page and pays no fee.
Threat Model: Schema Poisoning and the Research-Layer Supply Chain
I have written dedicated threat models for fraud proofs, oracle feeds, and NFT mint paths. Here is the one for research pipelines, stated in the same form.
Adversary. A project with capital and a research team that understands the extraction schema being used against it.
Capability. The adversary cannot forge the analyst's conclusions, but it can author source material β documentation, blog posts, governance forum posts, audit summaries, dashboards β whose structure maximizes cleanly extractable information points. The extraction step is a content-agnostic parser; it rewards documents that decompose neatly.
Objective. Maximize the number and specificity of populated cells in the downstream report while minimizing the number of cells that could be filled with adverse information. Structurally, this means suppressing the absence signals β the missing audit, the unvested allocation, the unfilled role, the undocumented parameter β because absence is exactly what an extraction schema cannot represent.
| Attack Vector | Mechanism | Detection Difficulty | Real-World Analog | |---|---|---|---| | Documentation flooding | Publish high-volume, well-structured docs so extraction fills every field | High β the output looks dense, and density reads as rigor | extcodesize returns 0 during construction | | Stale-fact persistence | Leave outdated metrics in indexable locations with strong SEO | High β the parser has no updatedAt field | latestRoundData() with unread updatedAt | | Null suppression | Never publish anything that would produce an empty, adverse cell | Very high β the schema emits no row for an absent fact | ecrecover returning address(0) unchecked | | Confidence laundering | Attach the framework's own honesty artifacts (disclaimers, confidence ratings) to low-confidence content | High β the warning is generated by the same pipeline | Proof verified against a poisoned setup | | Coverage padding | Supply nine low-value facts so the nine-dimension matrix renders full | Moderate β requires a reader with independent ground truth | A successful CALL to an EOA |
Impact assessment. The output of the attack is not a false report. It is a true report whose truth-content has been selected by the subject. This is worse than fabrication, because every individual cell survives verification, and the aggregate misleads. There is no single claim to challenge, which means there is no single correction to publish, which means the correction never propagates.
Mitigation. Twenty, in order of cost-effectiveness: the schema must be capable of emitting fewer rows than it has dimensions; every rendered row must carry a provenance field naming the source and its timestamp; a report whose empty-cell ratio exceeds roughly 60% should refuse to render as a report and instead render as a one-line request for data; and the pipeline's own outputs should be treated as untrusted inputs by anyone downstream of it, which in practice means never β under any circumstances β counting cells instead of reading them.
Contrarian: The Honest Blank Is More Dangerous Than the Confident Lie
Here is the angle that I keep coming back to, and it is the opposite of what a reader expects me to conclude.
The forty-kilobyte document full of N/A cells is not the problem. It is, by the standards of this industry, remarkably well-behaved. Compare it to the median bull market research note: a two-thousand-word piece with a fully populated techno-economic matrix, a valuation framework, a competitive landscape table, and a price target β every number traceable to somewhere, most of those somewheres being the project's own communications. That document does not say N/A. It says $4.2B TVL, and the TVL is double-counted, and the double-counting is a known property of the methodology, and the methodology is disclosed in a footnote that is disclosed in smaller type than the number itself.
The N/A document is more honest and less useful. The confident document is less honest and more useful β right up until it isn't, at which point the reader has already sized the position.
So the honest framework is not the safe one, and this is the part the coverage-maximizing designers miss. Honesty is not a damping function on risk. It is a trust-conferring asset that, like any trust-conferring asset, can be collateralized. A pipeline that refuses to fabricate has built a reserve of credibility. The next document out of the same pipeline β the one that has real information points, forty of them, sourced from a project's own documentation with the correct timestamps and no adversarial cross-checks β spends that reserve in a single transaction.
The honest blank is a credit facility. The question is who draws on it.
And there is a deeper point about the specific form the honesty took. The framework's most valuable output was a single checked box: information critically missing, risk assessment impossible. That line is correct. It is also generated by the same rendering engine that produced the sixty-one N/A rows, which means it costs the operator nothing, which means it can be emitted in exactly the same volume and with exactly the same automaticity as an actual risk assessment. The warning is free to produce and expensive to falsify. In a market where every analyst now has an LLM, warnings have become the cheapest possible way to look rigorous.
I have seen this pattern before, in 2021, when I declined influencer partnerships worth more than my annual income to do a line-by-line audit of the ERC-721A implementation headed for Azuki's mainnet launch. Most of that code was excellent. There was a subtle integer issue in the mint path under high concurrency that I reported privately; the team patched before launch; I took no compensation and routed the equivalent to a decentralized science grant. What I learned from the reaction β and the reaction was genuinely instructive, because it included several peers who told me I was leaving money on the table β was that the market does not price the check. It prices the announcement that a check occurred. The audited badge and the audit are different products, sold by the same vendors, and only one of them has a failure mode.
A checked box reading "information critically missing" is a badge. It is correct, it is free, and it is produced at scale. The only thing that distinguishes it from a real risk assessment is whether someone was willing to write it when there were thirty-nine other cells that could have been filled in instead.
Takeaway: The Null Check Becomes an Audit Primitive
I think the next twenty-four months produce a research-layer attack that nobody currently has a name for, and I think it looks like this: a project ships documentation engineered for machine extraction β structured, timestamped, complete, and true β with every adverse fact placed in a location the schema cannot represent. The downstream report comes out full, accurate, and misleading. Every claim in it survives an adversarial check. The aggregate is wrong. And when the position goes bad, there is no single number to point at, no fabrication to expose, no analyst to blame, because the analyst read the document correctly and the document was correct.
The defense is not better models. It is a single missing primitive: a schema that can express absent, propagate that absence through every downstream computation without collapsing it to zero, and refuse to render a row where the null originated. On-chain, we learned this the hard way: require(x != address(0)), updatedAt within tolerance, answeredInRound checked even when deprecated, dispute games that treat silence as unresolved rather than valid. Off-chain, we have not learned it at all.
Tracing the gas cost anomaly back to the EVM one more time: the chain charges 2,100 gas to read a slot that was never written, and it hands back a perfectly valid zero. That zero has cost real money. The forty kilobytes of N/A cost only credibility β the currency nobody thinks to meter, and the one every pipeline spends last.
Absence of evidence is not evidence of absence. It is also not a spreadsheet. The day a research framework learns to say I do not know in a font size large enough to be uncomfortable, the market will finally have something worth auditing.