Commit 9a56f54
feat(blockchain): advance XMSS preparation window preemptively (#332)
## 🗒️ Description / Motivation
This PR closes #262.
Every 65,536 slots, an XMSS signing key has to precompute its next
bottom tree via leansig's
[`advance_preparation`](https://github.com/leanEthereum/leanSig). The
two most recently computed trees form a sliding "prepared window" of
131,072 slots - the range the key can sign for without doing more work.
Once the wall-clock slot crosses out of that window, the precomputation
has to run before the next signature.
PR #261 made `advance_preparation()` run synchronously on the
`BlockChainServer` actor's tick handler. When the window has to slide
forward, the actor blocks on the hash work long enough to stall other
executions.
This PR moves that advance **off the signing path**, running it
preemptively where blocking is cheap:
- **At startup**, in `BlockChain::spawn` (before the actor starts
ticking) - catches each loaded key's prepared window up to the current
wall-clock slot. Handles long offline gaps.
- **At the end of every tick**, after the interval's duties - advances
each key's window to cover `slot + 1`, so the next tick's signing is
always inside the prepared window.
The lazy advance loop inside `sign_with_*` is kept as a safety net, with
added `elapsed_ms` timing logs so we'd see it if it ever fires.
## What Changed
**`crates/blockchain/src/key_manager.rs`**
- New `KeyManager::advance_keys_to(slot)` - iterates registered
validators and advances both attestation and proposal keys to cover
`slot`.
- New free helper `advance_key(...)` - synchronous advance loop with
`Instant::now()` timing. Emits `info!` at start, `info!` with
`elapsed_ms` at end, `warn!` on activation-interval exhaustion.
- Added matching `Instant::now()` + `elapsed_ms` `info!` to the
pre-existing advance loops in `sign_with_attestation_key` /
`sign_with_proposal_key`.
**`crates/blockchain/src/lib.rs`**
- `BlockChain::spawn`: computes current wall-clock slot and calls
`key_manager.advance_keys_to(current_slot)` before the actor starts
ticking.
- `on_tick`: at the very end, after metric updates, calls
`self.key_manager.advance_keys_to((slot + 1) as u32)`.
## Correctness / Behavior Guarantees
- Signing is never delayed by an advance - preempt runs at the idle tail
of the interval (or before any tick fires, at startup).
- Steady-state: the end-of-tick advance is a no-op in 65,535 out of
every 65,536 slots.
- After a long offline gap: startup catch-up walks the window forward
before any tick fires.
- Activation-interval exhaustion stays a hard error in the signing path;
`advance_key` logs `warn!` and breaks so the next sign attempt surfaces
the error.
- `ValidatorKeyPair` shape and the `KeyManagerError` enum are unchanged
from main.
## Tests Added / Run
- [x] `make fmt` clean
- [x] `make lint` clean
- [x] `make test` passes
- [ ] Boundary-crossing verification on devnet - only fires every 65,536
slots, deferred to operational verification. Log lines `Preparing XMSS
key for slot in background` (start) and `XMSS key advance complete`
(success) signal the path firing.
## Related Issues / PRs
- Initially linked to #262
- Follow-up to #261
---------
Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com>
Co-authored-by: Pablo Deymonnaz <pdeymon@fi.uba.ar>1 parent 22e56f1 commit 9a56f54
2 files changed
Lines changed: 62 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
8 | | - | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
51 | 60 | | |
52 | 61 | | |
53 | 62 | | |
| |||
85 | 94 | | |
86 | 95 | | |
87 | 96 | | |
| 97 | + | |
88 | 98 | | |
89 | 99 | | |
90 | 100 | | |
| |||
95 | 105 | | |
96 | 106 | | |
97 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
98 | 114 | | |
99 | 115 | | |
100 | 116 | | |
| |||
130 | 146 | | |
131 | 147 | | |
132 | 148 | | |
| 149 | + | |
133 | 150 | | |
134 | 151 | | |
135 | 152 | | |
| |||
140 | 157 | | |
141 | 158 | | |
142 | 159 | | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
143 | 166 | | |
144 | 167 | | |
145 | 168 | | |
| |||
153 | 176 | | |
154 | 177 | | |
155 | 178 | | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
156 | 201 | | |
157 | 202 | | |
158 | 203 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
67 | | - | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
68 | 80 | | |
69 | 81 | | |
70 | 82 | | |
| |||
195 | 207 | | |
196 | 208 | | |
197 | 209 | | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
198 | 213 | | |
199 | 214 | | |
200 | 215 | | |
| |||
0 commit comments