diff --git a/doc/api.md b/doc/api.md index e26e81b..5ace3c6 100644 --- a/doc/api.md +++ b/doc/api.md @@ -4,6 +4,7 @@ * [1.2 获取validator最近20笔质押变化](#1.2) * [1.3 获取validator的delegate记录](#1.3) * [1.4 获取validator的undelegate记录](#1.4) +* [1.5 获取validator最近10日vote变化](#1.5) ## [Contract](#2) * [2.1 获取bound数量](#2.1) @@ -343,8 +344,55 @@ } ``` +

1.5 获取validator最近10日vote变化

+* `GET /api/diff/vote` +* 参数 + +| 参数 | 类型 | 必传 | 说明 | +|-----------|--------|----|-------------| +| validator | string | N | validator地址 | +| page | number | N | 页码,默认1 | +| page_size | number | N | 页大小,默认10 | + +* Request: `http://localhost/api/diff/vote?validator=0x000e33ab7471186f3b1de9fc08bb9c480f453590&page=1&page_size=5` +* Response: +```json +{ + "total": 65, + "page": 1, + "page_size": 5, + "data": [ + { + "block_num": 5475318, + "should_vote": 1135, + "voted": 1135 + }, + { + "block_num": 5475317, + "should_vote": 1134, + "voted": 1134 + }, + { + "block_num": 5475316, + "should_vote": 1134, + "voted": 1134 + }, + { + "block_num": 5475314, + "should_vote": 1131, + "voted": 1131 + }, + { + "block_num": 5475313, + "should_vote": 1130, + "voted": 1130 + } + ] +} +``` +

2.1 获取bound数量

* `GET /api/bound` diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 695452a..575974e 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -15,7 +15,7 @@ use crate::delegate::get_delegate_records; use crate::receipt::get_receipts; use crate::stake::get_stake_records; use crate::undelegate::get_undelegate_records; -use crate::validators::{get_latest20, get_validators}; +use crate::validators::{get_latest20, get_validator_votes, get_validators}; use axum::http::Method; use axum::routing::get; use axum::Router; @@ -96,6 +96,7 @@ async fn main() -> Result<()> { .route("/api/diff/latest", get(get_latest20)) .route("/api/records/delegate", get(get_delegate_records)) .route("/api/records/undelegate", get(get_undelegate_records)) + .route("/api/diff/vote", get(get_validator_votes)) .route("/api/records/stake", get(get_stake_records)) .route("/api/receipts", get(get_receipts)) .route("/api/bound", get(get_delegator_bound)) diff --git a/indexer/src/types.rs b/indexer/src/types.rs index cd9ebf8..1f7e3c8 100644 --- a/indexer/src/types.rs +++ b/indexer/src/types.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; + #[derive(Serialize, Deserialize)] pub struct QueryResult { pub total: i64, @@ -8,6 +9,13 @@ pub struct QueryResult { pub data: T, } +#[derive(Serialize, Deserialize)] +pub struct ValidatorVoteResponse { + pub block_num: i64, + pub should_vote: i32, + pub voted: i32, +} + #[derive(Serialize, Deserialize)] pub struct DelegatorSumResponse { pub delegate: String, diff --git a/indexer/src/validators.rs b/indexer/src/validators.rs index 5d01998..cb6a7e5 100644 --- a/indexer/src/validators.rs +++ b/indexer/src/validators.rs @@ -1,5 +1,7 @@ use crate::error::Result; -use crate::types::{QueryResult, ValidatorLatest20Response, ValidatorResponse}; +use crate::types::{ + QueryResult, ValidatorLatest20Response, ValidatorResponse, ValidatorVoteResponse, +}; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; @@ -11,6 +13,62 @@ use sqlx::Row; use std::ops::{Add, Sub}; use std::sync::Arc; +#[derive(Serialize, Deserialize)] +pub struct GetVoteParams { + pub validator: String, + pub page: Option, + pub page_size: Option, +} + +const BLOCKS_PER_DAY: i64 = 24 * 60 * 60 / 15; // 5760 + +pub async fn get_validator_votes( + State(state): State>, + params: Query, +) -> Result>>> { + let mut pool = state.pool.acquire().await?; + let page = params.page.unwrap_or(1); + let page_size = params.page_size.unwrap_or(10); + + let sql_total = r#"SELECT count(*) FROM evm_validators WHERE validator = $1 + AND block_num >= (SELECT max(block_num) FROM evm_validators) - $2"#; + let row = sqlx::query(sql_total) + .bind(¶ms.0.validator) + .bind(BLOCKS_PER_DAY) + .fetch_one(&mut *pool) + .await?; + let total: i64 = row.try_get("count")?; + + let sql_query = r#"SELECT block_num,should_vote,voted FROM evm_validators WHERE + validator = $1 AND block_num >= (SELECT max(block_num) FROM evm_validators) - $2 + ORDER BY block_num DESC LIMIT $3 OFFSET $4"#; + let rows = sqlx::query(sql_query) + .bind(¶ms.0.validator) + .bind(BLOCKS_PER_DAY) + .bind(page_size) + .bind((page - 1) * page_size) + .fetch_all(&mut *pool) + .await?; + let mut votes: Vec = vec![]; + for r in rows { + let block_num: i64 = r.try_get("block_num")?; + let should_vote: i32 = r.try_get("should_vote")?; + let voted: i32 = r.try_get("voted")?; + votes.push(ValidatorVoteResponse { + block_num, + should_vote, + voted, + }) + } + + Ok(Json(QueryResult { + total, + page, + page_size, + data: votes, + })) +} + #[derive(Serialize, Deserialize)] pub struct GetValidatorsParams { pub online: Option,