diff --git a/chain/src/main.rs b/chain/src/main.rs index 716f8604..9ca75aa3 100644 --- a/chain/src/main.rs +++ b/chain/src/main.rs @@ -136,6 +136,12 @@ async fn crawling_fn( .await .into_rpc_error()?; + tracing::info!("Query first block in epoch..."); + let first_block_in_epoch = + namada_service::get_first_block_in_epoch(&client) + .await + .into_rpc_error()?; + let block = Block::from( tm_block_response, &block_results, @@ -198,6 +204,7 @@ async fn crawling_fn( let crawler_state = ChainCrawlerState { last_processed_block: block_height, last_processed_epoch: epoch, + first_block_in_epoch, timestamp: timestamp_in_sec, }; @@ -269,6 +276,9 @@ async fn initial_query( namada_service::get_epoch_at_block_height(client, block_height) .await .into_rpc_error()?; + let first_block_in_epoch = namada_service::get_first_block_in_epoch(client) + .await + .into_rpc_error()?; loop { let pos_crawler_state = @@ -317,6 +327,7 @@ async fn initial_query( let crawler_state = ChainCrawlerState { last_processed_block: block_height, last_processed_epoch: epoch, + first_block_in_epoch, timestamp, }; diff --git a/chain/src/repository/crawler_state.rs b/chain/src/repository/crawler_state.rs index 25ea57f6..c8db448f 100644 --- a/chain/src/repository/crawler_state.rs +++ b/chain/src/repository/crawler_state.rs @@ -22,6 +22,8 @@ pub fn upsert_crawler_state( .eq(excluded(crawler_state::last_processed_block)), crawler_state::last_processed_epoch .eq(excluded(crawler_state::last_processed_epoch)), + crawler_state::first_block_in_epoch + .eq(excluded(crawler_state::first_block_in_epoch)), )) .execute(transaction_conn) .context("Failed to update crawler state in db")?; diff --git a/chain/src/services/db.rs b/chain/src/services/db.rs index 9da65834..4793c1bb 100644 --- a/chain/src/services/db.rs +++ b/chain/src/services/db.rs @@ -19,6 +19,7 @@ pub async fn get_chain_crawler_state( .select(( crawler_state::dsl::last_processed_block, crawler_state::dsl::last_processed_epoch, + crawler_state::dsl::first_block_in_epoch, crawler_state::dsl::timestamp, )) .first(conn) @@ -30,6 +31,7 @@ pub async fn get_chain_crawler_state( Ok(ChainCrawlerState { last_processed_block: crawler_state.last_processed_block as BlockHeight, last_processed_epoch: crawler_state.last_processed_epoch as Epoch, + first_block_in_epoch: crawler_state.first_block_in_epoch as BlockHeight, timestamp: crawler_state.timestamp.and_utc().timestamp(), }) } diff --git a/chain/src/services/namada.rs b/chain/src/services/namada.rs index f020fd41..4b2bc20f 100644 --- a/chain/src/services/namada.rs +++ b/chain/src/services/namada.rs @@ -38,6 +38,18 @@ pub async fn get_native_token(client: &HttpClient) -> anyhow::Result { Ok(Id::from(native_token)) } +pub async fn get_first_block_in_epoch( + client: &HttpClient, +) -> anyhow::Result { + let block_height = RPC + .shell() + .first_block_height_of_current_epoch(client) + .await + .context("Failed to query native token")?; + + Ok(block_height.0 as BlockHeight) +} + pub async fn get_epoch_at_block_height( client: &HttpClient, block_height: BlockHeight, diff --git a/orm/migrations/2024-07-04-103941_crawler_state/up.sql b/orm/migrations/2024-07-04-103941_crawler_state/up.sql index 24b1870f..5beddcc1 100644 --- a/orm/migrations/2024-07-04-103941_crawler_state/up.sql +++ b/orm/migrations/2024-07-04-103941_crawler_state/up.sql @@ -5,6 +5,7 @@ CREATE TYPE CRAWLER_NAME AS ENUM ('chain', 'governance', 'parameters', 'pos', 'r CREATE TABLE crawler_state ( name CRAWLER_NAME PRIMARY KEY NOT NULL, last_processed_block INT, + first_block_in_epoch INT, last_processed_epoch INT, timestamp TIMESTAMP NOT NULL ); diff --git a/orm/src/crawler_state.rs b/orm/src/crawler_state.rs index 2a317146..90b8c647 100644 --- a/orm/src/crawler_state.rs +++ b/orm/src/crawler_state.rs @@ -55,6 +55,7 @@ pub struct CrawlerStateDb { pub name: CrawlerNameDb, pub last_processed_block: Option, pub last_processed_epoch: Option, + pub first_block_in_epoch: Option, pub timestamp: chrono::NaiveDateTime, } @@ -62,11 +63,13 @@ pub struct CrawlerStateDb { pub struct ChainCrawlerStateDb { pub last_processed_block: i32, pub last_processed_epoch: i32, + pub first_block_in_epoch: i32, pub timestamp: chrono::NaiveDateTime, } impl Queryable< ( + Nullable, Nullable, Nullable, diesel::sql_types::Timestamp, @@ -74,17 +77,19 @@ impl Pg, > for ChainCrawlerStateDb { - type Row = (Option, Option, chrono::NaiveDateTime); + type Row = (Option, Option, Option, chrono::NaiveDateTime); fn build(row: Self::Row) -> diesel::deserialize::Result { match row { ( Some(last_processed_block), Some(last_processed_epoch), + Some(first_block_in_epoch), timestamp, ) => Ok(Self { last_processed_block, last_processed_epoch, + first_block_in_epoch, timestamp, }), _ => Err("last_processed_block or last_processed_epoch missing \ @@ -167,6 +172,7 @@ pub struct ChainStateInsertDb { pub name: CrawlerNameDb, pub last_processed_block: i32, pub last_processed_epoch: i32, + pub first_block_in_epoch: i32, pub timestamp: chrono::NaiveDateTime, } @@ -219,6 +225,7 @@ impl From<(CrawlerName, ChainCrawlerState)> for ChainStateInsertDb { name: crawler_name.into(), last_processed_block: state.last_processed_block as i32, last_processed_epoch: state.last_processed_epoch as i32, + first_block_in_epoch: state.first_block_in_epoch as i32, timestamp, } } diff --git a/orm/src/schema.rs b/orm/src/schema.rs index ad7f4d0b..9e90f252 100644 --- a/orm/src/schema.rs +++ b/orm/src/schema.rs @@ -109,6 +109,7 @@ diesel::table! { crawler_state (name) { name -> CrawlerName, last_processed_block -> Nullable, + first_block_in_epoch -> Nullable, last_processed_epoch -> Nullable, timestamp -> Timestamp, } diff --git a/shared/src/crawler_state.rs b/shared/src/crawler_state.rs index 63874b27..4d56d48d 100644 --- a/shared/src/crawler_state.rs +++ b/shared/src/crawler_state.rs @@ -13,6 +13,7 @@ pub enum CrawlerName { pub struct ChainCrawlerState { pub last_processed_block: BlockHeight, pub last_processed_epoch: Epoch, + pub first_block_in_epoch: Epoch, pub timestamp: i64, } diff --git a/webserver/src/repository/chain.rs b/webserver/src/repository/chain.rs index a70c6af7..85f07463 100644 --- a/webserver/src/repository/chain.rs +++ b/webserver/src/repository/chain.rs @@ -66,6 +66,7 @@ impl ChainRepositoryTrait for ChainRepository { .select(( crawler_state::dsl::last_processed_block, crawler_state::dsl::last_processed_epoch, + crawler_state::dsl::first_block_in_epoch, crawler_state::dsl::timestamp, )) .first(conn) diff --git a/webserver/src/response/governance.rs b/webserver/src/response/governance.rs index 6519c544..e1d37216 100644 --- a/webserver/src/response/governance.rs +++ b/webserver/src/response/governance.rs @@ -118,12 +118,11 @@ impl Proposal { min_num_of_blocks: i32, min_duration: i32, ) -> Self { - // TODO: It would be better to save first block height of current epoch - // in state and use that here, otherwise if any epoch had - // different number of blocks than min_num_of_blocks - // this will be off - let epoch_progress = - epoch_progress(chain_state.last_processed_block, min_num_of_blocks); + let epoch_progress = epoch_progress( + chain_state.last_processed_block, + chain_state.first_block_in_epoch, + min_num_of_blocks, + ); let to_start = time_between_epochs( min_num_of_blocks, diff --git a/webserver/src/response/pos.rs b/webserver/src/response/pos.rs index 102e583c..3f8c3e65 100644 --- a/webserver/src/response/pos.rs +++ b/webserver/src/response/pos.rs @@ -178,8 +178,11 @@ impl Unbond { min_num_of_blocks: i32, min_duration: i32, ) -> Self { - let epoch_progress = - epoch_progress(chain_state.last_processed_block, min_num_of_blocks); + let epoch_progress = epoch_progress( + chain_state.last_processed_block, + chain_state.first_block_in_epoch, + min_num_of_blocks, + ); let to_withdraw = time_between_epochs( min_num_of_blocks, diff --git a/webserver/src/response/utils.rs b/webserver/src/response/utils.rs index ee58adff..a7026249 100644 --- a/webserver/src/response/utils.rs +++ b/webserver/src/response/utils.rs @@ -35,9 +35,11 @@ where } } -pub fn epoch_progress(current_block: i32, min_num_of_blocks: i32) -> f64 { - // Not sure why but real min number of blocks is usually 2 more what is in - // store +pub fn epoch_progress( + current_block: i32, + first_block_in_epoch: i32, + min_num_of_blocks: i32, +) -> f64 { let min_num_of_blocks = min_num_of_blocks + (EPOCH_SWITCH_BLOCKS_DELAY as i32); @@ -46,7 +48,7 @@ pub fn epoch_progress(current_block: i32, min_num_of_blocks: i32) -> f64 { let current_block = current_block - 1; // Calculate the block in the current epoch - let block_in_current_epoch = current_block % min_num_of_blocks; + let block_in_current_epoch = current_block - first_block_in_epoch; // Calculate how much into the epoch we are block_in_current_epoch as f64 / min_num_of_blocks as f64