1use rhdl::prelude::*;
34
35use crate::cert::{ROLE_PREPARE, share_context};
36use crate::cert::collector::popcount16;
37
38pub mod kind {
40 pub const PREPARE: u128 = 1;
41 pub const COMMIT: u128 = 2;
42 pub const PROMISE: u128 = 3;
43 pub const FASTCOMMIT: u128 = 4;
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
48pub struct ConsConfig {
49 pub init: bool,
50 pub n: b5,
51 pub me: b5,
52 pub session: b64,
53 pub fast_wait: b32,
55}
56
57#[derive(Clone, Copy, Debug, PartialEq, Digital)]
59pub struct ConsMsg<const P: usize> {
60 pub valid: bool,
61 pub from: b5,
62 pub kind: b4,
63 pub view: b32,
64 pub instance: b32,
65 pub digest: [b64; 4],
66 pub len: b5,
67 pub value: [b32; P],
68}
69
70#[derive(Clone, Copy, Debug, PartialEq, Digital)]
72pub struct Proposal<const P: usize> {
73 pub valid: bool,
74 pub len: b5,
75 pub value: [b32; P],
76}
77
78#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
80pub struct ConsDigest {
81 pub valid: bool,
82 pub epoch: b32,
83 pub slot: b3,
84 pub instance: b32,
85 pub digest: [b64; 4],
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
90pub struct ConsSigned {
91 pub valid: bool,
92 pub epoch: b32,
93 pub slot: b3,
94 pub instance: b32,
95 pub sig: [b64; 8],
96}
97
98#[derive(Clone, Copy, Debug, PartialEq, Digital)]
100pub struct Constraint<const P: usize> {
101 pub set: bool,
102 pub instance: b32,
103 pub digest: [b64; 4],
104 pub len: b5,
105 pub value: [b32; P],
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Digital)]
113pub struct Install<const G: usize, const P: usize> {
114 pub valid: bool,
115 pub skip: bool,
116 pub late: bool,
118 pub view: b32,
119 pub c: [Constraint<P>; G],
120}
121
122#[derive(Clone, Copy, Debug, PartialEq, Digital)]
124pub struct SlotView<const P: usize> {
125 pub active: bool,
126 pub instance: b32,
127 pub dig_have: bool,
128 pub digest: [b64; 4],
129 pub len: b5,
130 pub value: [b32; P],
131 pub kview: b32,
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Digital)]
137pub struct ConsIn<const G: usize, const P: usize> {
138 pub cfg: ConsConfig,
139 pub sealing: bool,
142 pub install: Install<G, P>,
143 pub pending: bool,
147 pub ctb: ConsMsg<P>,
149 pub p2p: ConsMsg<P>,
151 pub proposal: Proposal<P>,
152 pub digest: ConsDigest,
153 pub signed: ConsSigned,
154 pub certified: [bool; G],
156 pub ctb_ready: bool,
157 pub p2p_ready: bool,
158 pub digest_ready: bool,
159 pub sign_ready: bool,
160 pub own_ready: bool,
161 pub open_ready: bool,
162 pub decide_ready: bool,
163}
164
165#[derive(Clone, Copy, Debug, PartialEq, Digital)]
167pub struct ConsDigestReq<const P: usize> {
168 pub valid: bool,
169 pub epoch: b32,
170 pub slot: b3,
171 pub instance: b32,
172 pub len: b5,
173 pub value: [b32; P],
174}
175
176#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
178pub struct ConsSignReq {
179 pub valid: bool,
180 pub epoch: b32,
181 pub slot: b3,
182 pub instance: b32,
183 pub context: [b64; 6],
184}
185
186#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
188pub struct ConsKey {
189 pub valid: bool,
190 pub view: b32,
191 pub instance: b32,
192 pub digest: [b64; 4],
193 pub sig: [b64; 8],
194}
195
196#[derive(Clone, Copy, Debug, PartialEq, Digital)]
198pub struct Decision<const P: usize> {
199 pub valid: bool,
200 pub instance: b32,
201 pub view: b32,
202 pub len: b5,
203 pub value: [b32; P],
204 pub slow: bool,
205}
206
207#[derive(Clone, Copy, Debug, PartialEq, Digital)]
209pub struct ConsOut<const G: usize, const P: usize> {
210 pub ctb_ready: bool,
211 pub p2p_ready: bool,
212 pub proposal_ready: bool,
213 pub ctb_send: ConsMsg<P>,
215 pub p2p_send: ConsMsg<P>,
218 pub share_send: ConsKey,
219 pub digest_req: ConsDigestReq<P>,
220 pub sign_req: ConsSignReq,
221 pub open: ConsKey,
222 pub own: ConsKey,
223 pub decide: Decision<P>,
224 pub view: b32,
225 pub leader: b5,
226 pub stalled: bool,
228 pub bridge_done: bool,
230 pub slots: [SlotView<P>; G],
231 pub dropped: b32,
232}
233
234#[derive(Clone, Copy, Debug, PartialEq, Digital)]
236pub struct CSlot<const P: usize> {
237 pub active: bool,
238 pub instance: b32,
239 pub len: b5,
240 pub value: [b32; P],
241 pub dig_sent: bool,
242 pub dig_have: bool,
243 pub digest: [b64; 4],
244 pub start: b32,
245 pub promised: b16,
246 pub promise_sent: bool,
247 pub fastc: b16,
248 pub fastc_sent: bool,
249 pub opened: bool,
250 pub sign_sent: bool,
251 pub signed: bool,
252 pub sig: [b64; 8],
253 pub own_given: bool,
254 pub share_sent: bool,
255 pub commit_sent: bool,
256 pub commits: b16,
258 pub decided: bool,
259 pub slow: bool,
260 pub from_commit: bool,
263 pub kview: b32,
268 pub claim_set: bool,
270 pub claimed: [b64; 4],
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Digital)]
275pub struct ConsState<const G: usize, const P: usize> {
276 pub configured: bool,
277 pub epoch: b32,
278 pub n: b5,
279 pub me: b5,
280 pub q: b5,
281 pub all: b16,
282 pub session: b64,
283 pub fast_wait: b32,
284 pub view: b32,
285 pub clock: b32,
286 pub progress: b32,
288 pub no_nv: bool,
290 pub backoff: b3,
294 pub next_decide: b32,
296 pub next_propose: b32,
297 pub s: [CSlot<P>; G],
298 pub c: [Constraint<P>; G],
300 pub h_ctb: ConsMsg<P>,
301 pub h_p2p: ConsMsg<P>,
302 pub h_share: ConsKey,
303 pub h_dig: ConsDigestReq<P>,
304 pub h_sign: ConsSignReq,
305 pub h_open: ConsKey,
306 pub h_own: ConsKey,
307 pub h_dec: Decision<P>,
308 pub dropped: b32,
309}
310
311#[kernel]
313pub fn empty_cslot<const P: usize>() -> CSlot<P> {
314 CSlot::<P> {
315 active: false,
316 instance: b32(0),
317 len: b5(0),
318 value: [b32(0); P],
319 dig_sent: false,
320 dig_have: false,
321 digest: [b64(0); 4],
322 start: b32(0),
323 promised: b16(0),
324 promise_sent: false,
325 fastc: b16(0),
326 fastc_sent: false,
327 opened: false,
328 sign_sent: false,
329 signed: false,
330 sig: [b64(0); 8],
331 own_given: false,
332 share_sent: false,
333 commit_sent: false,
334 commits: b16(0),
335 decided: false,
336 slow: false,
337 from_commit: false,
338 kview: b32(0),
339 claim_set: false,
340 claimed: [b64(0); 4],
341 }
342}
343
344#[kernel]
346pub fn empty_constraint<const P: usize>() -> Constraint<P> {
347 Constraint::<P> { set: false, instance: b32(0), digest: [b64(0); 4], len: b5(0), value: [b32(0); P] }
348}
349
350#[kernel]
352pub fn idle_msg<const P: usize>() -> ConsMsg<P> {
353 ConsMsg::<P> { valid: false, from: b5(0), kind: b4(0), view: b32(0), instance: b32(0), digest: [b64(0); 4], len: b5(0), value: [b32(0); P] }
354}
355
356#[kernel]
358pub fn idle_key() -> ConsKey {
359 ConsKey { valid: false, view: b32(0), instance: b32(0), digest: [b64(0); 4], sig: [b64(0); 8] }
360}
361
362#[kernel]
364pub fn idle_decision<const P: usize>() -> Decision<P> {
365 Decision::<P> { valid: false, instance: b32(0), view: b32(0), len: b5(0), value: [b32(0); P], slow: false }
366}
367
368#[kernel]
370pub fn leader_of(view: b32, n: b5) -> b5 {
371 let d: b32 = n.resize();
373 let mut rem = b32(0);
374 for k in 0..32 {
375 rem = (rem << b32(1)) | ((view >> b32((31 - k) as u128)) & b32(1));
376 if rem >= d {
377 rem = rem - d;
378 }
379 }
380 rem.resize()
381}
382
383impl<const G: usize, const P: usize> ConsState<G, P> {
384 pub fn idle() -> Self {
385 Self {
386 configured: false,
387 epoch: b32(0),
388 n: b5(0),
389 me: b5(0),
390 q: b5(0),
391 all: b16(0),
392 session: b64(0),
393 fast_wait: b32(0),
394 view: b32(0),
395 clock: b32(0),
396 progress: b32(0),
397 no_nv: false,
398 backoff: b3(0),
399 next_decide: b32(0),
400 next_propose: b32(0),
401 s: [empty_cslot::<P>(); G],
402 c: [empty_constraint::<P>(); G],
403 h_ctb: idle_msg::<P>(),
404 h_p2p: idle_msg::<P>(),
405 h_share: idle_key(),
406 h_dig: ConsDigestReq::<P> { valid: false, epoch: b32(0), slot: b3(0), instance: b32(0), len: b5(0), value: [b32(0); P] },
407 h_sign: ConsSignReq::default(),
408 h_open: idle_key(),
409 h_own: idle_key(),
410 h_dec: idle_decision::<P>(),
411 dropped: b32(0),
412 }
413 }
414}
415
416impl<const G: usize, const P: usize> Default for ConsState<G, P> {
417 fn default() -> Self {
418 Self::idle()
419 }
420}
421
422impl<const P: usize> Default for ConsMsg<P> {
423 fn default() -> Self {
424 idle_msg::<P>()
425 }
426}
427
428impl<const P: usize> Default for Proposal<P> {
429 fn default() -> Self {
430 Self { valid: false, len: b5(0), value: [b32(0); P] }
431 }
432}
433
434impl<const G: usize, const P: usize> Default for ConsIn<G, P> {
435 fn default() -> Self {
436 Self {
437 cfg: ConsConfig::default(),
438 ctb: ConsMsg::default(),
439 p2p: ConsMsg::default(),
440 proposal: Proposal::default(),
441 digest: ConsDigest::default(),
442 signed: ConsSigned::default(),
443 certified: [false; G],
444 sealing: false,
445 pending: false,
446 install: Install::<G, P> { valid: false, skip: false, late: false, view: b32(0), c: [empty_constraint::<P>(); G] },
447 ctb_ready: false,
448 p2p_ready: false,
449 digest_ready: false,
450 sign_ready: false,
451 own_ready: false,
452 open_ready: false,
453 decide_ready: false,
454 }
455 }
456}
457
458#[kernel]
460pub fn cons_step<const G: usize, const P: usize>(i: ConsIn<G, P>, r: ConsState<G, P>) -> (ConsOut<G, P>, ConsState<G, P>) {
461 let mut s = r;
462 let gmask = b32(G as u128) - b32(1);
463 let g32 = b32(G as u128);
464 if i.cfg.init {
465 s = r;
466 s.configured = i.cfg.n >= b5(3) && i.cfg.n <= b5(16) && i.cfg.me < i.cfg.n && (i.cfg.n & b5(1)) == b5(1) && i.cfg.session != b64(0);
467 s.epoch = r.epoch + b32(1);
468 s.n = i.cfg.n;
469 s.me = i.cfg.me;
470 s.q = (i.cfg.n >> b5(1)) + b5(1);
471 let mut all = b16(0);
472 for k in 0..16 {
473 if b5(k as u128) < i.cfg.n {
474 all = all | (b16(1) << b16(k as u128));
475 }
476 }
477 s.all = all;
478 s.session = i.cfg.session;
479 s.fast_wait = i.cfg.fast_wait;
480 s.view = b32(0);
481 s.clock = b32(0);
482 s.progress = b32(0);
483 s.no_nv = false;
484 s.backoff = b3(0);
485 s.next_decide = b32(0);
486 s.next_propose = b32(0);
487 for k in 0..G {
488 s.s[k] = empty_cslot::<P>();
489 s.c[k] = empty_constraint::<P>();
490 }
491 s.h_ctb = idle_msg::<P>();
492 s.h_p2p = idle_msg::<P>();
493 s.h_share = idle_key();
494 s.h_dig.valid = false;
495 s.h_sign.valid = false;
496 s.h_open = idle_key();
497 s.h_own = idle_key();
498 s.h_dec = idle_decision::<P>();
499 s.dropped = b32(0);
500 }
501 let run = r.configured && !i.cfg.init;
502 let leader = leader_of(r.view, r.n);
503 let me_bit = b16(1) << r.me.resize::<16>();
504 s.clock = r.clock + b32(1);
505
506 let ck: b3 = (i.ctb.instance & gmask).resize();
508 let ce = r.s[ck];
509 let c_win = i.ctb.instance >= r.next_decide && i.ctb.instance < r.next_decide + g32;
510 let c_ahead = i.ctb.instance >= r.next_decide + g32;
512 let next_view = r.view + b32(1);
517 let ctb_next = i.ctb.valid && i.ctb.view == next_view && (i.ctb.kind == b4(kind::PREPARE) || i.ctb.kind == b4(kind::COMMIT));
518 let is_commit = i.ctb.kind == b4(kind::COMMIT);
519 let ctb_early = ctb_next
520 || (i.ctb.valid && i.ctb.view == r.view && i.ctb.instance >= r.next_decide && c_ahead)
521 || (i.ctb.valid
524 && is_commit
525 && i.ctb.view <= r.view
526 && i.ctb.instance >= r.next_decide
527 && (c_ahead || (c_win && ce.active && ce.instance == i.ctb.instance && !ce.dig_have)));
528 let pk: b3 = (i.p2p.instance & gmask).resize();
529 let pe = r.s[pk];
530 let p_win = i.p2p.instance >= r.next_decide && i.p2p.instance < r.next_decide + g32;
531 let p2p_early = (i.p2p.valid && i.p2p.view == next_view)
532 || (i.p2p.valid && i.p2p.view == r.view && i.p2p.instance >= r.next_decide && (!p_win || !(pe.active && pe.instance == i.p2p.instance && pe.dig_have)));
533 let mut o = ConsOut::<G, P> {
534 ctb_ready: run && !ctb_early,
535 p2p_ready: run && !p2p_early,
536 proposal_ready: false,
537 ctb_send: r.h_ctb,
538 p2p_send: r.h_p2p,
539 share_send: r.h_share,
540 digest_req: r.h_dig,
541 sign_req: r.h_sign,
542 open: r.h_open,
543 own: r.h_own,
544 decide: r.h_dec,
545 view: r.view,
546 leader: leader,
547 stalled: false,
548 bridge_done: false,
549 slots: [SlotView::<P> { active: false, instance: b32(0), dig_have: false, digest: [b64(0); 4], len: b5(0), value: [b32(0); P], kview: b32(0) }; G],
550 dropped: r.dropped,
551 };
552 for k in 0..G {
553 let e = r.s[k];
554 o.slots[k] = SlotView::<P> { active: e.active, instance: e.instance, dig_have: e.dig_have, digest: e.digest, len: e.len, value: e.value, kview: e.kview };
555 }
556 if i.cfg.init {
557 o.ctb_send.valid = false;
558 o.p2p_send.valid = false;
559 o.share_send.valid = false;
560 o.digest_req.valid = false;
561 o.sign_req.valid = false;
562 o.open.valid = false;
563 o.own.valid = false;
564 o.decide.valid = false;
565 }
566 if !i.cfg.init {
568 if r.h_ctb.valid && i.ctb_ready {
569 s.h_ctb.valid = false;
570 }
571 if r.h_p2p.valid && i.p2p_ready {
572 s.h_p2p.valid = false;
573 }
574 if r.h_share.valid && i.p2p_ready && !r.h_p2p.valid {
575 s.h_share.valid = false;
576 }
577 if r.h_dig.valid && i.digest_ready {
578 s.h_dig.valid = false;
579 }
580 if r.h_sign.valid && i.sign_ready {
581 s.h_sign.valid = false;
582 }
583 if r.h_open.valid && i.open_ready {
584 s.h_open.valid = false;
585 }
586 if r.h_own.valid && i.own_ready {
587 s.h_own.valid = false;
588 }
589 if r.h_dec.valid && i.decide_ready {
590 s.h_dec.valid = false;
591 }
592 }
593 if r.h_p2p.valid {
595 o.share_send.valid = false;
596 }
597
598 if run && i.digest.valid && i.digest.epoch == r.epoch {
600 let k = i.digest.slot;
601 if s.s[k].active && s.s[k].instance == i.digest.instance && s.s[k].dig_sent && !s.s[k].dig_have {
602 s.s[k].dig_have = true;
603 s.s[k].digest = i.digest.digest;
604 let cc = s.c[k];
607 if cc.set && cc.instance == i.digest.instance && cc.digest != i.digest.digest && !s.s[k].from_commit {
608 s.s[k] = empty_cslot::<P>();
609 s.dropped = s.dropped + b32(1);
610 }
611 if s.s[k].claim_set && s.s[k].claimed != i.digest.digest {
614 s.s[k].commits = b16(0);
615 if s.s[k].from_commit {
616 s.s[k] = empty_cslot::<P>();
619 }
620 }
621 }
622 }
623 if run && i.signed.valid && i.signed.epoch == r.epoch {
624 let k = i.signed.slot;
625 if s.s[k].active && s.s[k].instance == i.signed.instance && s.s[k].sign_sent && !s.s[k].signed {
626 s.s[k].signed = true;
627 s.s[k].sig = i.signed.sig;
628 }
629 }
630
631 if run && i.ctb.valid && !ctb_early {
633 let m = i.ctb;
634 let in_window = m.instance >= r.next_decide && m.instance < r.next_decide + g32;
635 let k: b3 = (m.instance & gmask).resize();
636 let e = s.s[k];
637 if m.kind == b4(kind::PREPARE) {
638 let fresh = !(e.active && e.instance == m.instance) || (e.from_commit && !e.decided);
642 let ok = m.from == leader && m.view == r.view && in_window && fresh && m.len <= b5(P as u128) && !i.sealing && !r.no_nv;
643 if ok {
644 let mut n = empty_cslot::<P>();
645 n.active = true;
646 n.instance = m.instance;
647 n.len = m.len;
648 n.value = m.value;
649 n.start = r.clock;
650 n.kview = r.view;
653 if e.active && e.instance == m.instance && e.from_commit && e.kview == r.view {
654 n.commits = e.commits;
655 n.claim_set = true;
656 n.claimed = if e.dig_have { e.digest } else { e.claimed };
657 }
658 s.s[k] = n;
659 } else {
660 s.dropped = s.dropped + b32(1);
661 }
662 } else if m.kind == b4(kind::COMMIT) {
663 let key = e.active && e.instance == m.instance && e.dig_have && m.view == e.kview && m.digest == e.digest;
668 let missed = !(e.active && e.instance == m.instance) && m.view <= r.view && in_window && m.len <= b5(P as u128);
671 if key && m.from < r.n {
672 s.s[k].commits = e.commits | (b16(1) << m.from.resize::<16>());
673 } else if missed && m.from < r.n {
674 let mut n = empty_cslot::<P>();
677 n.active = true;
678 n.from_commit = true;
679 n.kview = m.view;
680 n.instance = m.instance;
681 n.len = m.len;
682 n.value = m.value;
683 n.start = r.clock;
684 n.claim_set = true;
685 n.claimed = m.digest;
686 n.commits = b16(1) << m.from.resize::<16>();
687 n.promise_sent = true;
689 n.fastc_sent = true;
690 n.sign_sent = true;
691 n.signed = true;
692 n.own_given = true;
693 n.share_sent = true;
694 n.commit_sent = true;
695 s.s[k] = n;
696 } else {
697 s.dropped = s.dropped + b32(1);
698 }
699 } else {
700 s.dropped = s.dropped + b32(1);
701 }
702 }
703
704 if run && i.p2p.valid && !p2p_early {
706 let m = i.p2p;
707 let k: b3 = (m.instance & gmask).resize();
708 let e = s.s[k];
709 let key = e.active && e.instance == m.instance && e.dig_have && e.kview == r.view && m.view == r.view && m.digest == e.digest && m.from < r.n && m.from != r.me;
711 let bit = b16(1) << m.from.resize::<16>();
712 if key && m.kind == b4(kind::PROMISE) {
713 s.s[k].promised = e.promised | bit;
714 } else if key && m.kind == b4(kind::FASTCOMMIT) {
715 s.s[k].fastc = e.fastc | bit;
716 } else {
717 s.dropped = s.dropped + b32(1);
718 }
719 }
720
721 let room = r.next_propose < r.next_decide + g32;
724 let am_leader = r.me == leader && !r.no_nv;
725 if run && am_leader && room && !r.h_ctb.valid {
726 let pk: b3 = (r.next_propose & gmask).resize();
727 let pc = r.c[pk];
728 let constrained = pc.set && pc.instance == r.next_propose;
729 o.proposal_ready = !constrained && !i.sealing;
730 if constrained && !i.sealing {
731 s.h_ctb = ConsMsg::<P> { valid: true, from: r.me, kind: b4(kind::PREPARE), view: r.view, instance: r.next_propose, digest: [b64(0); 4], len: pc.len, value: pc.value };
732 s.next_propose = r.next_propose + b32(1);
733 } else if i.proposal.valid && i.proposal.len <= b5(P as u128) && !i.sealing {
734 s.h_ctb = ConsMsg::<P> {
735 valid: true,
736 from: r.me,
737 kind: b4(kind::PREPARE),
738 view: r.view,
739 instance: r.next_propose,
740 digest: [b64(0); 4],
741 len: i.proposal.len,
742 value: i.proposal.value,
743 };
744 s.next_propose = r.next_propose + b32(1);
745 }
746 }
747
748 let mut d_done = r.h_dig.valid;
750 let mut x_done = r.h_p2p.valid;
751 let mut g_done = r.h_sign.valid;
752 let mut k_done = r.h_open.valid;
753 let mut w_done = r.h_own.valid;
754 let mut h_done = r.h_share.valid;
755 let mut c_done = r.h_ctb.valid || s.h_ctb.valid;
756 for k in 0..G {
757 let e = r.s[k];
758 let slot = b3(k as u128);
759 if run && e.active && (!e.decided || (i.sealing && e.fastc_sent)) {
762 if !d_done && !e.dig_sent {
763 d_done = true;
764 s.h_dig = ConsDigestReq::<P> { valid: true, epoch: r.epoch, slot: slot, instance: e.instance, len: e.len, value: e.value };
765 s.s[k].dig_sent = true;
766 }
767 if !k_done && e.dig_have && !e.opened {
768 k_done = true;
769 s.h_open = ConsKey { valid: true, view: e.kview, instance: e.instance, digest: e.digest, sig: [b64(0); 8] };
770 s.s[k].opened = true;
771 }
772 if !x_done && e.dig_have && !e.promise_sent {
773 x_done = true;
774 s.h_p2p = ConsMsg::<P> { valid: true, from: r.me, kind: b4(kind::PROMISE), view: r.view, instance: e.instance, digest: e.digest, len: b5(0), value: [b32(0); P] };
775 s.s[k].promise_sent = true;
776 s.s[k].promised = s.s[k].promised | me_bit;
777 } else if !x_done && e.promise_sent && (e.promised | me_bit) == r.all && !e.fastc_sent {
778 x_done = true;
779 s.h_p2p = ConsMsg::<P> { valid: true, from: r.me, kind: b4(kind::FASTCOMMIT), view: r.view, instance: e.instance, digest: e.digest, len: b5(0), value: [b32(0); P] };
780 s.s[k].fastc_sent = true;
781 s.s[k].fastc = s.s[k].fastc | me_bit;
782 }
783 let late = r.clock - e.start >= r.fast_wait || (i.sealing && e.fastc_sent);
787 if !g_done && e.dig_have && e.opened && late && !e.sign_sent {
788 g_done = true;
789 s.h_sign = ConsSignReq { valid: true, epoch: r.epoch, slot: slot, instance: e.instance, context: share_context(b8(ROLE_PREPARE), r.view, e.instance, e.digest) };
790 s.s[k].sign_sent = true;
791 }
792 if !w_done && e.signed && !e.own_given {
793 w_done = true;
794 s.h_own = ConsKey { valid: true, view: r.view, instance: e.instance, digest: e.digest, sig: e.sig };
795 s.s[k].own_given = true;
796 }
797 if !h_done && e.signed && !e.share_sent {
798 h_done = true;
799 s.h_share = ConsKey { valid: true, view: r.view, instance: e.instance, digest: e.digest, sig: e.sig };
800 s.s[k].share_sent = true;
801 }
802 if !c_done && e.own_given && i.certified[k] && !e.commit_sent {
803 c_done = true;
804 s.h_ctb = ConsMsg::<P> { valid: true, from: r.me, kind: b4(kind::COMMIT), view: r.view, instance: e.instance, digest: e.digest, len: e.len, value: e.value };
805 s.s[k].commit_sent = true;
806 }
807 }
808 }
809
810 let hk: b3 = (r.next_decide & gmask).resize();
813 let h = r.s[hk];
814 let held = h.active && h.instance == r.next_decide && h.dig_have;
815 let commits = if i.certified[hk] { popcount16(h.commits) } else { b5(0) };
817 let fast = held && h.fastc == r.all;
818 let slow = held && commits >= r.q;
819 if run && held && !h.decided && (fast || slow) && !r.h_dec.valid {
820 s.h_dec = Decision::<P> { valid: true, instance: h.instance, view: h.kview, len: h.len, value: h.value, slow: !fast };
821 s.s[hk].decided = true;
822 s.next_decide = r.next_decide + b32(1);
823 s.progress = r.clock;
824 s.backoff = b3(0);
825 }
826 let window2 = (r.fast_wait + r.fast_wait) << r.backoff.resize::<32>();
829 o.stalled = run && ((held && !h.decided && (r.clock - h.start >= window2)) || (i.pending && r.clock - r.progress >= window2));
830 let mut bridge = true;
831 for k in 0..G {
832 let e = r.s[k];
833 if e.active && e.fastc_sent && !e.from_commit && !e.commit_sent {
834 bridge = false;
835 }
836 }
837 o.bridge_done = run && i.sealing && bridge;
838
839 if run && i.install.valid && i.install.view == r.view + b32(1) {
843 s.view = i.install.view;
844 s.next_propose = r.next_decide;
845 s.progress = r.clock;
846 s.no_nv = i.install.skip;
847 s.backoff = if r.backoff < b3(6) { r.backoff + b3(1) } else { r.backoff };
848 for k in 0..G {
849 let keep = r.s[k].active && r.s[k].from_commit && !r.s[k].decided;
852 if !keep {
853 s.s[k] = empty_cslot::<P>();
854 }
855 s.c[k] = i.install.c[k];
856 }
857 s.h_ctb.valid = false;
858 s.h_p2p.valid = false;
859 s.h_share.valid = false;
860 s.h_sign.valid = false;
861 s.h_open.valid = false;
862 s.h_own.valid = false;
863 s.epoch = r.epoch + b32(1);
864 }
865 if run && i.install.valid && i.install.late && i.install.view == r.view && r.no_nv {
869 s.no_nv = false;
870 s.next_propose = r.next_decide;
871 s.progress = r.clock;
872 for k in 0..G {
873 let keep = r.s[k].active && r.s[k].from_commit && !r.s[k].decided;
874 if !keep {
875 s.s[k] = empty_cslot::<P>();
876 }
877 s.c[k] = i.install.c[k];
878 }
879 s.h_ctb.valid = false;
880 s.h_p2p.valid = false;
881 s.h_share.valid = false;
882 s.h_sign.valid = false;
883 s.h_open.valid = false;
884 s.h_own.valid = false;
885 s.epoch = r.epoch + b32(1);
886 }
887 (o, s)
888}