Skip to content

Commit 735acc7

Browse files
authored
feat(fortuna): Improve startup flow (#2638)
* fix(fortuna): Do not wait for all chains setup in startup * Use blocking thread for calculating hashchain * Put block timestamp lag next to other tracking tasks * Retry startup
1 parent 676ee6c commit 735acc7

File tree

11 files changed

+283
-272
lines changed

11 files changed

+283
-272
lines changed

apps/fortuna/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/fortuna/src/api.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub struct ApiMetrics {
4343

4444
#[derive(Clone)]
4545
pub struct ApiState {
46-
pub chains: Arc<HashMap<ChainId, BlockchainState>>,
46+
pub chains: Arc<RwLock<HashMap<ChainId, ApiBlockChainState>>>,
4747

4848
pub metrics_registry: Arc<RwLock<Registry>>,
4949

@@ -53,7 +53,7 @@ pub struct ApiState {
5353

5454
impl ApiState {
5555
pub async fn new(
56-
chains: HashMap<ChainId, BlockchainState>,
56+
chains: Arc<RwLock<HashMap<ChainId, ApiBlockChainState>>>,
5757
metrics_registry: Arc<RwLock<Registry>>,
5858
) -> ApiState {
5959
let metrics = ApiMetrics {
@@ -68,7 +68,7 @@ impl ApiState {
6868
);
6969

7070
ApiState {
71-
chains: Arc::new(chains),
71+
chains,
7272
metrics: Arc::new(metrics),
7373
metrics_registry,
7474
}
@@ -94,6 +94,12 @@ pub struct BlockchainState {
9494
pub confirmed_block_status: BlockStatus,
9595
}
9696

97+
#[derive(Clone)]
98+
pub enum ApiBlockChainState {
99+
Uninitialized,
100+
Initialized(BlockchainState),
101+
}
102+
97103
pub enum RestError {
98104
/// The caller passed a sequence number that isn't within the supported range
99105
InvalidSequenceNumber,
@@ -108,6 +114,9 @@ pub enum RestError {
108114
/// The server cannot currently communicate with the blockchain, so is not able to verify
109115
/// which random values have been requested.
110116
TemporarilyUnavailable,
117+
/// The server is not able to process the request because the blockchain initialization
118+
/// has not been completed yet.
119+
Uninitialized,
111120
/// A catch-all error for all other types of errors that could occur during processing.
112121
Unknown,
113122
}
@@ -137,6 +146,11 @@ impl IntoResponse for RestError {
137146
"This service is temporarily unavailable",
138147
)
139148
.into_response(),
149+
RestError::Uninitialized => (
150+
StatusCode::SERVICE_UNAVAILABLE,
151+
"The service is not yet initialized for this chain, please try again in a few minutes",
152+
)
153+
.into_response(),
140154
RestError::Unknown => (
141155
StatusCode::INTERNAL_SERVER_ERROR,
142156
"An unknown error occurred processing the request",
@@ -172,6 +186,7 @@ pub fn get_register_uri(base_uri: &str, chain_id: &str) -> Result<String> {
172186

173187
#[cfg(test)]
174188
mod test {
189+
use crate::api::ApiBlockChainState;
175190
use {
176191
crate::{
177192
api::{self, ApiState, BinaryEncoding, Blob, BlockchainState, GetRandomValueResponse},
@@ -228,10 +243,16 @@ mod test {
228243
};
229244

230245
let mut chains = HashMap::new();
231-
chains.insert("ethereum".into(), eth_state);
232-
chains.insert("avalanche".into(), avax_state);
246+
chains.insert(
247+
"ethereum".into(),
248+
ApiBlockChainState::Initialized(eth_state),
249+
);
250+
chains.insert(
251+
"avalanche".into(),
252+
ApiBlockChainState::Initialized(avax_state),
253+
);
233254

234-
let api_state = ApiState::new(chains, metrics_registry).await;
255+
let api_state = ApiState::new(Arc::new(RwLock::new(chains)), metrics_registry).await;
235256

236257
let app = api::routes(api_state);
237258
(TestServer::new(app).unwrap(), eth_read, avax_read)

apps/fortuna/src/api/chain_ids.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ responses(
1515
pub async fn chain_ids(
1616
State(state): State<crate::api::ApiState>,
1717
) -> Result<Json<Vec<ChainId>>, RestError> {
18-
let chain_ids = state.chains.iter().map(|(id, _)| id.clone()).collect();
18+
let chain_ids = state
19+
.chains
20+
.read()
21+
.await
22+
.iter()
23+
.map(|(id, _)| id.clone())
24+
.collect();
1925
Ok(Json(chain_ids))
2026
}

apps/fortuna/src/api/revelation.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::api::ApiBlockChainState;
12
use crate::chain::reader::BlockNumber;
23
use {
34
crate::api::{ChainId, RequestLabel, RestError},
@@ -46,8 +47,18 @@ pub async fn revelation(
4647

4748
let state = state
4849
.chains
50+
.read()
51+
.await
4952
.get(&chain_id)
50-
.ok_or(RestError::InvalidChainId)?;
53+
.ok_or(RestError::InvalidChainId)?
54+
.clone();
55+
56+
let state = match state {
57+
ApiBlockChainState::Initialized(state) => state,
58+
ApiBlockChainState::Uninitialized => {
59+
return Err(RestError::Uninitialized);
60+
}
61+
};
5162

5263
let current_block_number_fut = state
5364
.contract

apps/fortuna/src/command/register_provider.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,16 @@ pub async fn register_provider_from_config(
5252

5353
let commitment_length = provider_config.chain_length;
5454
tracing::info!("Generating hash chain");
55-
let chain = PebbleHashChain::from_config(
55+
let chain = PebbleHashChain::from_config_async(
5656
&secret,
5757
chain_id,
5858
&private_key_string.parse::<LocalWallet>()?.address(),
5959
&chain_config.contract_addr,
6060
&random,
6161
commitment_length,
6262
provider_config.chain_sample_interval,
63-
)?;
63+
)
64+
.await?;
6465
tracing::info!("Done generating hash chain");
6566

6667
// Arguments to the contract to register our new provider.

0 commit comments

Comments
 (0)