Skip to content

Commit fd4c237

Browse files
committed
feat: add a consolidated endpoint for current and prior sortitions
1 parent 0146ba2 commit fd4c237

File tree

4 files changed

+207
-109
lines changed

4 files changed

+207
-109
lines changed

stacks-signer/src/chainstate.rs

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use stacks_common::types::chainstate::{ConsensusHash, StacksPublicKey};
2525
use stacks_common::util::hash::Hash160;
2626
use stacks_common::{info, warn};
2727

28-
use crate::client::{ClientError, StacksClient};
28+
use crate::client::{ClientError, CurrentAndLastSortition, StacksClient};
2929
use crate::config::SignerConfig;
3030
use crate::signerdb::{BlockState, SignerDb};
3131

@@ -138,8 +138,6 @@ pub struct SortitionsView {
138138
pub last_sortition: Option<SortitionState>,
139139
/// the current successful sortition (this corresponds to the "current" miner slot)
140140
pub cur_sortition: SortitionState,
141-
/// the hash at which the sortitions view was fetched
142-
pub latest_consensus_hash: ConsensusHash,
143141
/// configuration settings for evaluating proposals
144142
pub config: ProposalEvalConfig,
145143
}
@@ -608,42 +606,21 @@ impl SortitionsView {
608606
config: ProposalEvalConfig,
609607
client: &StacksClient,
610608
) -> Result<Self, ClientError> {
611-
let latest_state = client.get_latest_sortition()?;
612-
let latest_ch = latest_state.consensus_hash;
613-
614-
// figure out what cur_sortition will be set to.
615-
// if the latest sortition wasn't successful, query the last one that was.
616-
let latest_success = if latest_state.was_sortition {
617-
latest_state
618-
} else {
619-
info!("Latest state wasn't a sortition: {latest_state:?}");
620-
let last_sortition_ch = latest_state
621-
.last_sortition_ch
622-
.as_ref()
623-
.ok_or_else(|| ClientError::NoSortitionOnChain)?;
624-
client.get_sortition(last_sortition_ch)?
625-
};
626-
627-
// now, figure out what `last_sortition` will be set to.
628-
let last_sortition = latest_success
629-
.last_sortition_ch
630-
.as_ref()
631-
.map(|ch| client.get_sortition(ch))
632-
.transpose()?;
609+
let CurrentAndLastSortition {
610+
current_sortition,
611+
last_sortition,
612+
} = client.get_current_and_last_sortition()?;
633613

634-
let cur_sortition = SortitionState::try_from(latest_success)?;
614+
let cur_sortition = SortitionState::try_from(current_sortition)?;
635615
let last_sortition = last_sortition
636616
.map(SortitionState::try_from)
637617
.transpose()
638618
.ok()
639619
.flatten();
640620

641-
let latest_consensus_hash = latest_ch;
642-
643621
Ok(Self {
644622
cur_sortition,
645623
last_sortition,
646-
latest_consensus_hash,
647624
config,
648625
})
649626
}

stacks-signer/src/client/stacks_client.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ struct GetStackersErrorResp {
8888
err_msg: String,
8989
}
9090

91+
/// Result from fetching current and last sortition:
92+
/// two sortition infos
93+
pub struct CurrentAndLastSortition {
94+
/// the latest winning sortition in the current burnchain fork
95+
pub current_sortition: SortitionInfo,
96+
/// the last winning sortition prior to `current_sortition`, if there was one
97+
pub last_sortition: Option<SortitionInfo>,
98+
}
99+
91100
impl From<&GlobalConfig> for StacksClient {
92101
fn from(config: &GlobalConfig) -> Self {
93102
Self {
@@ -484,6 +493,47 @@ impl StacksClient {
484493
Ok(tenures)
485494
}
486495

496+
/// Get the current winning sortition and the last winning sortition
497+
pub fn get_current_and_last_sortition(&self) -> Result<CurrentAndLastSortition, ClientError> {
498+
debug!("stacks_node_client: Getting current and prior sortition...");
499+
let path = format!("{}/latest_and_last", self.sortition_info_path());
500+
let timer = crate::monitoring::new_rpc_call_timer(&path, &self.http_origin);
501+
let send_request = || {
502+
self.stacks_node_client.get(&path).send().map_err(|e| {
503+
warn!("Signer failed to request latest sortition"; "err" => ?e);
504+
e
505+
})
506+
};
507+
let response = send_request()?;
508+
timer.stop_and_record();
509+
if !response.status().is_success() {
510+
return Err(ClientError::RequestFailure(response.status()));
511+
}
512+
let mut info_list: VecDeque<SortitionInfo> = response.json()?;
513+
let Some(current_sortition) = info_list.pop_front() else {
514+
return Err(ClientError::UnexpectedResponseFormat(
515+
"Empty SortitionInfo returned".into(),
516+
));
517+
};
518+
if !current_sortition.was_sortition {
519+
return Err(ClientError::UnexpectedResponseFormat(
520+
"'Current' SortitionInfo returned which was not a winning sortition".into(),
521+
));
522+
}
523+
let last_sortition = if current_sortition.last_sortition_ch.is_some() {
524+
let Some(last_sortition) = info_list.pop_back() else {
525+
return Err(ClientError::UnexpectedResponseFormat("'Current' SortitionInfo has `last_sortition_ch` field, but corresponding data not returned".into()));
526+
};
527+
Some(last_sortition)
528+
} else {
529+
None
530+
};
531+
Ok(CurrentAndLastSortition {
532+
current_sortition,
533+
last_sortition,
534+
})
535+
}
536+
487537
/// Get the sortition information for the latest sortition
488538
pub fn get_latest_sortition(&self) -> Result<SortitionInfo, ClientError> {
489539
debug!("stacks_node_client: Getting latest sortition...");

0 commit comments

Comments
 (0)