| 596 | debug!( |
| 597 | ?round, |
| 598 | parent_view = parent.0.get(), |
| 599 | parent_digest = ?parent.1, |
| 600 | "proposal step 1: fetching parent block" |
| 601 | ); |
| 602 | #[cfg(feature = "prom")] |
| 603 | let parent_fetch_start = std::time::Instant::now(); |
| 604 | let parent_block = if parent.1 == self.genesis_hash.into() { |
| 605 | Either::Left(future::ready(Ok(Block::genesis(self.genesis_hash)))) |
| 606 | } else { |
| 607 | let parent_round = if parent.0.get() == 0 { |
| 608 | // Parent view is 0, which means that this is the first block of the epoch |
| 609 | None |
| 610 | } else { |
| 611 | Some(Round::new(round.epoch(), parent.0)) |
| 612 | }; |
| 613 | Either::Right( |
| 614 | syncer |
| 615 | .subscribe(parent_round, parent.1) |
| 616 | .await |
| 617 | .map(|x| x.context("parent block subscription canceled")), |
| 618 | ) |
| 619 | }; |
| 620 | // The syncer cancels (drops) a subscription for a round older than its |
| 621 | // last_processed_round. Propagate that as an Err so the Propose handler |
| 622 | // aborts the proposal gracefully instead of panicking. |
| 623 | let parent_block = parent_block.await?; |
| 624 | |
| 625 | #[cfg(feature = "prom")] |
| 626 | { |
| 627 | let parent_fetch_duration = parent_fetch_start.elapsed().as_millis() as f64; |
| 628 | histogram!("handle_proposal_parent_fetch_duration_millis") |
| 629 | .record(parent_fetch_duration); |
| 630 | } |
| 631 | |
| 632 | // STEP 2: Wait for finalizer notification |
| 633 | debug!( |
| 634 | ?round, |
| 635 | parent_height = parent_block.height(), |
| 636 | parent_digest = ?parent_block.digest(), |
| 637 | "proposal step 2: waiting for finalizer notification" |
| 638 | ); |
| 639 | #[cfg(feature = "prom")] |
| 640 | let finalizer_wait_start = std::time::Instant::now(); |
| 641 | // now that we have the parent additionally await for that to be executed by the finalizer |
| 642 | let parent_height = parent_block.height(); |
| 643 | let parent_digest = parent_block.digest(); |
| 644 | let rx = finalizer |
| 645 | .notify_at_height(parent_height, parent_digest) |
| 646 | .await; |
| 647 | // await for notification |
| 648 | if !rx.await.expect("Finalizer dropped") { |
| 649 | debug!( |
| 650 | "Aborting block proposal for epoch {} and height {} because of an outdated height notification", |
| 651 | round.epoch().get(), |
| 652 | parent_height + 1, |
| 653 | ); |
| 654 | return Err(anyhow!( |
| 655 | "Aborting block proposal for epoch {} and height {} because of an outdated height notification", |