penumbra_sdk_sct/component/
clock.rs1use crate::{epoch::Epoch, state_key};
2use anyhow::{anyhow, Context, Result};
3use async_trait::async_trait;
4use cnidarium::{StateRead, StateWrite};
5use penumbra_sdk_proto::{StateReadProto, StateWriteProto};
6use std::str::FromStr;
7
8#[async_trait]
9pub trait EpochRead: StateRead {
11 async fn get_block_height(&self) -> Result<u64> {
16 self.get_proto(state_key::block_manager::block_height())
17 .await?
18 .ok_or_else(|| anyhow!("Missing block_height"))
19 }
20
21 async fn get_current_block_timestamp(&self) -> Result<tendermint::Time> {
29 let timestamp_string: String = self
30 .get_proto(state_key::block_manager::current_block_timestamp())
31 .await?
32 .ok_or_else(|| anyhow!("Missing current_block_timestamp"))?;
33
34 Ok(tendermint::Time::from_str(×tamp_string)
35 .context("current_block_timestamp was an invalid RFC3339 time string")?)
36 }
37
38 async fn get_block_timestamp(&self, height: u64) -> Result<tendermint::Time> {
46 let timestamp_string: String = self
47 .nonverifiable_get_proto(&state_key::block_manager::block_timestamp(height).as_bytes())
48 .await?
49 .ok_or_else(|| anyhow!("Missing block_timestamp for height {}", height))?;
50
51 Ok(
52 tendermint::Time::from_str(×tamp_string).context(format!(
53 "block_timestamp for height {} was an invalid RFC3339 time string",
54 height
55 ))?,
56 )
57 }
58
59 async fn get_current_epoch(&self) -> Result<Epoch> {
64 let height = self.get_block_height().await?;
66
67 self.get(&state_key::epoch_manager::epoch_by_height(height))
68 .await?
69 .ok_or_else(|| anyhow!("missing epoch for current height: {height}"))
70 }
71
72 async fn get_epoch_by_height(&self, height: u64) -> Result<Epoch> {
77 self.get(&state_key::epoch_manager::epoch_by_height(height))
78 .await?
79 .ok_or_else(|| anyhow!("missing epoch for height"))
80 }
81
82 async fn is_epoch_ending_early(&self) -> bool {
84 self.object_get(state_key::epoch_manager::end_epoch_early())
85 .unwrap_or(false)
86 }
87}
88
89impl<T: StateRead + ?Sized> EpochRead for T {}
90
91#[async_trait]
95pub trait EpochManager: StateWrite {
96 fn put_block_timestamp(&mut self, height: u64, timestamp: tendermint::Time) {
100 self.put_proto(
101 state_key::block_manager::current_block_timestamp().into(),
102 timestamp.to_rfc3339(),
103 );
104
105 self.nonverifiable_put_proto(
106 state_key::block_manager::block_timestamp(height).into(),
107 timestamp.to_rfc3339(),
108 );
109 }
110
111 fn set_end_epoch_flag(&mut self) {
114 self.object_put(state_key::epoch_manager::end_epoch_early(), true)
115 }
116
117 fn put_block_height(&mut self, height: u64) {
119 self.put_proto(state_key::block_manager::block_height().to_string(), height)
120 }
121
122 fn put_epoch_by_height(&mut self, height: u64, epoch: Epoch) {
124 self.put(state_key::epoch_manager::epoch_by_height(height), epoch)
125 }
126}
127
128impl<T: StateWrite + ?Sized> EpochManager for T {}