Skip to content

Add wait_for_new_round to Creator trait to eliminate round-change polling #153

@bagelface

Description

@bagelface

Background

The orchestrator's run loop currently polls get_payload_and_round() in a tight loop (with a 2s sleep) after executing a round, waiting for on-chain state to advance before starting the next round. This is a consequence of Creator only exposing a snapshot API — the orchestrator has no way to block until the round actually changes.

Problem

The polling approach has a few downsides:

  • It requires the orchestrator to maintain a HashSet<u64> of executed rounds to avoid re-broadcasting Start for the same round
  • The 2s poll interval is an arbitrary constant — too short wastes calls to the provider, too long adds latency to the start of the next round
  • The orchestrator is doing work that semantically belongs to the Creator

Proposed Change

Add a wait_for_new_round(current: u64) -> Result<(Vec<u8>, u64)> method to the Creator trait that blocks until the round advances past current:

pub trait Creator {
    type TaskData;

    async fn get_payload_and_round(&self) -> Result<(Vec<u8>, u64)>;
    async fn wait_for_new_round(&self, current: u64) -> Result<(Vec<u8>, u64)>;
    fn get_task_metadata(&self) -> Self::TaskData;
}

The orchestrator's post-execution path then becomes:

// After successful execution:
executed_round = current_round;
// inner loop drains until continue_time as normal, then:
let (payload, current_round) = self.task_creator.wait_for_new_round(executed_round).await?;
// guaranteed fresh round, no HashSet needed

CounterCreator (and other implementations) can implement this by polling the provider internally with appropriate backoff, keeping that logic out of the orchestrator.

Benefits

  • Eliminates executed_rounds: HashSet<u64> from the orchestrator
  • Eliminates the 2s polling constant
  • Correct by construction — the orchestrator cannot re-execute the same round because it blocks until a new one is available
  • Provider polling strategy (interval, backoff) lives in the Creator implementation where it has context about the underlying data source

Related

Introduced as a follow-up to the fix in #[PR for bagelface/fix-retrigger-after-threshold-bug].

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestlatencyFeatures related to latency improvementspriority:mediumImportant but not urgent
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions