Commit 3e3a5c7
committed
perf(consensus): cache shielded bundle verification
Every shielded proof and signature is verified twice: once when the
transaction arrives over mempool gossip, and again when it arrives inside
a block. Zebra used to avoid the second pass by skipping whole-transaction
verification for block transactions already accepted into the mempool, and
removed that in #10494 as a security fix without replacing it.
The reason that bypass kept breaking is structural: it cached
`valid(tx, height, block time, spent outputs)` under a key that did not
determine that proposition. Expiry, lock time, the consensus branch id,
the Orchard soft-fork gates and the proof-size rule all move with height,
and the network upgrade even selects which Orchard circuit verifying key
applies, so a stale verdict could answer a different question than the one
being asked.
Cache the bundle verification itself instead. `verify(bundle, sighash, vk)`
is a pure function, so a hit is bit-identical to the computation it
replaces. On a hit the transaction verifier still runs end to end at the
block's height, with the block's time and the block's spent outputs; only
one `oneshot` inside `verify_sapling_bundle` or `queue_orchard_bundle` is
short-circuited.
That makes key completeness the whole of the safety argument. An entry is
keyed by the transaction's unmined ID, the sighash it was verified against,
and the shielded pool the bundle sits in:
* the ID determines the bundle. A witnessed ID's ZIP 244 authorizing-data
digest commits to the proofs and signatures, which the txid alone does
not - that was CVE-2026-34377. A v4 transaction's legacy ID is the hash
of the whole serialization, which carries the same authorizing data;
* the sighash is named separately because it is not always a function of
the transaction alone: a v5 or v6 sighash also commits to the amounts
and scripts of the spent transparent outputs, and a v4 shielded sighash
commits to the block's consensus branch id, which a v4 ID does not;
* the pool separates the Orchard and Ironwood bundles of one v6
transaction, which share an ID and a sighash;
* the verifying key is committed to structurally: each Orchard circuit
version already has its own verifier, so it now also has its own cache,
and an entry can only be read back under the key it was written
against. Sapling has one key pair for all of history.
Only `Ok` results are recorded. A batch error is not per-item evidence,
since `Fallback` resolves batch failures by re-verifying each item singly,
and an error out of the service need not be a verdict at all - it can
report that the batch worker shut down. Recording that as "invalid" would
make the node reject a valid block. For the same reason `Cached::poll_ready`
does not delegate to the inner service: callers poll before they call, so
delegating would surface a dead batch worker's error for an item whose
result the cache already holds. The miss path acquires inner readiness
inside `call`, which also stops hits from holding `Batch`'s semaphore
permits.
Items built without a witnessed transaction ID are verified every time.
Each cache holds 20,000 keys - several blocks of history plus a full
mempool - and reports hits, misses, inserts, evictions and size under
`zebra.consensus.cache.*`, labelled by the same `verifier` names as
`zebra.consensus.batch.duration_seconds`.
Tests: cache-key completeness for both verifiers over real mainnet bundles;
the cache's own behaviour (hit, miss, eviction, no reuse across items, no
memory of failures, cancellation, readiness) against a stub verifier; a
real Sapling bundle rejected when replayed under another branch id; and two
end-to-end tests through the transaction verifiers showing that a mempool
verification is reused by the block that mines the transaction, that the
block one height past expiry is still rejected, and that an
authorizing-data twin with an identical txid is fully re-verified and
rejected.1 parent 0a43e0e commit 3e3a5c7
9 files changed
Lines changed: 2257 additions & 53 deletions
File tree
- zebra-consensus/src
- primitives
- cache
- halo2
- sapling
- transaction
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
21 | 24 | | |
22 | 25 | | |
23 | 26 | | |
| |||
26 | 29 | | |
27 | 30 | | |
28 | 31 | | |
29 | | - | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
30 | 36 | | |
31 | 37 | | |
32 | 38 | | |
| |||
110 | 116 | | |
111 | 117 | | |
112 | 118 | | |
113 | | - | |
114 | | - | |
115 | | - | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
116 | 124 | | |
117 | 125 | | |
118 | 126 | | |
119 | 127 | | |
120 | 128 | | |
121 | 129 | | |
122 | 130 | | |
| 131 | + | |
123 | 132 | | |
124 | 133 | | |
125 | 134 | | |
| |||
130 | 139 | | |
131 | 140 | | |
132 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
133 | 146 | | |
134 | 147 | | |
135 | 148 | | |
136 | 149 | | |
137 | 150 | | |
138 | 151 | | |
139 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
140 | 176 | | |
141 | 177 | | |
142 | 178 | | |
| |||
156 | 192 | | |
157 | 193 | | |
158 | 194 | | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
159 | 213 | | |
160 | 214 | | |
161 | 215 | | |
162 | 216 | | |
163 | 217 | | |
164 | | - | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
165 | 224 | | |
166 | 225 | | |
167 | 226 | | |
| |||
221 | 280 | | |
222 | 281 | | |
223 | 282 | | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
224 | 286 | | |
225 | 287 | | |
226 | 288 | | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
231 | 294 | | |
232 | 295 | | |
233 | 296 | | |
| |||
236 | 299 | | |
237 | 300 | | |
238 | 301 | | |
239 | | - | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
240 | 315 | | |
241 | 316 | | |
242 | 317 | | |
| |||
257 | 332 | | |
258 | 333 | | |
259 | 334 | | |
260 | | - | |
| 335 | + | |
261 | 336 | | |
262 | 337 | | |
263 | 338 | | |
| |||
268 | 343 | | |
269 | 344 | | |
270 | 345 | | |
271 | | - | |
| 346 | + | |
272 | 347 | | |
273 | 348 | | |
274 | 349 | | |
| |||
281 | 356 | | |
282 | 357 | | |
283 | 358 | | |
284 | | - | |
| 359 | + | |
285 | 360 | | |
286 | 361 | | |
287 | 362 | | |
| |||
337 | 412 | | |
338 | 413 | | |
339 | 414 | | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
340 | 424 | | |
341 | 425 | | |
342 | 426 | | |
| |||
0 commit comments