Skip to content

Conversation

@aoikurokawa
Copy link
Collaborator

@aoikurokawa aoikurokawa commented Nov 13, 2025

Problem

  • We have to get RebalanceDirected instructions through as fast as possible at the start of an epoch

Solution

  • After executing every operation, the keeper check epoch info
  • If epoch transitioned, execute steward instructions (RebalanceDirected) immediately.

Flow changes

  1. Check epoch schedule, if epoch is transitioned, execute steward instructions
  2. Pick operations based on tick and interval
  3. Execute operation
  4. If executed operation was heavy (send many txs), check epoch info after finishing operation
  5. back to 3 until executing all operations
  6. back to 1
image

### Problem

- We have to get `RebalanceDirected` instructions through as fast as
possible at the start of an epoch

### Solution

- After executing every operation, the keeper check epoch info
- If epoch transitioned, execute steward instructions
(RebalanceDirected) immediately.

Flow
<img width="4224" height="3392" alt="image"
src="https://github.com/user-attachments/assets/3d3626e7-5b94-47d3-96fd-f7a125736786"
/>
@aoikurokawa aoikurokawa marked this pull request as ready for review November 14, 2025 00:15
@aoikurokawa aoikurokawa changed the title Keeper: Execute steward operation when epoch transition occured Keeper: Execute Steward operation immediately on epoch transition Nov 14, 2025
@gzalz
Copy link
Contributor

gzalz commented Nov 17, 2025

The logic here checks out but I do think that we can get even more aggressive with the timing. In this setup we will prioritize the directed rebalance next in the queue. The tasks in the queue can be quite heavy and there's potential for a non-trivial amount of time to pass before rebalance directed is removed from the queue.

Curious to hear thoughts from others on maybe using something like the slot stream from a geyser RPC plugin on a separate task? Or is that overkill? @ebatsell @CoachChuckFF @mrmizz

}
}

async fn check_and_fire_steward_on_epoch_transition(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional here should actually be if the Stake Pool has updated, last_updated_epoch I think this is the field. Since increase/decrease commands are locked until that has completed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, changed the if condition

    /// Check `last_update_epoch` field in Stake Pool
    ///
    /// # Process
    ///
    /// 1. Check the field `last_update_epoch` in StakePool account
    /// 2. If the `last_update_epoch` has updated, trigger steward operation
    /// 3. Otherwise, continue next operation
    pub async fn check_last_update_epoch(
        &mut self,
        client: Arc<RpcClient>,
        last_seen_epoch: &mut Option<u64>,
    ) -> bool {
        if let Some(all_steward_accounts) = self.all_steward_accounts.as_ref() {
            if let Ok(stake_pool) =
                get_stake_pool_account(&client, &all_steward_accounts.stake_pool_address).await
            {
                if let Some(ref mut seen_epoch) = last_seen_epoch {
                    let has_updated = stake_pool.last_update_epoch > *seen_epoch;
                    *seen_epoch = stake_pool.last_update_epoch;
                    return has_updated;
                } else {
                    *last_seen_epoch = Some(stake_pool.last_update_epoch);
                    return false;
                }
            }
        }

        false
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants