Skip to content

Commit

Permalink
added validator state (#39)
Browse files Browse the repository at this point in the history
* added validator state

* added my-validator endpoint

* added route

* more fixes
  • Loading branch information
Fraccaman authored Jun 4, 2024
1 parent d3d6cda commit c460ea7
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 14 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]
resolver = "2"

members = ["chain", "shared", "rewards", "orm", "pos", "governance", "webserver", "seeder", "parameters"]
members = ["chain", "shared", "rewards", "orm", "pos", "governance", "webserver", "seeder"]

[workspace.package]
authors = ["Heliax <[email protected]>"]
Expand Down Expand Up @@ -46,6 +46,7 @@ namada_governance = { git = "https://github.com/anoma/namada", tag = "v0.38.1" }
namada_ibc = { git = "https://github.com/anoma/namada", tag = "v0.38.1" }
namada_token = { git = "https://github.com/anoma/namada", tag = "v0.38.1" }
namada_parameters = { git = "https://github.com/anoma/namada", tag = "v0.38.1" }
namada_proof_of_stake = { git = "https://github.com/anoma/namada", tag = "v0.38.1" }
tendermint = "0.36.0"
tendermint-config = "0.36.0"
tendermint-rpc = { version = "0.36.0", features = ["http-client"] }
Expand Down
1 change: 1 addition & 0 deletions orm/migrations/2024-04-30-081808_init_validators/down.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
-- This file should undo anything in `up.sql`
DROP TYPE VALIDATOR_STATE;

DROP TABLE IF EXISTS validators;
5 changes: 4 additions & 1 deletion orm/migrations/2024-04-30-081808_init_validators/up.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
-- Your SQL goes here

CREATE TYPE VALIDATOR_STATE AS ENUM ('active', 'inactive', 'jailed');

CREATE TABLE validators (
id SERIAL PRIMARY KEY,
namada_address VARCHAR NOT NULL,
Expand All @@ -11,7 +13,8 @@ CREATE TABLE validators (
website VARCHAR,
description VARCHAR,
discord_handle VARCHAR,
avatar VARCHAR
avatar VARCHAR,
state VALIDATOR_STATE NOT NULL
);

ALTER TABLE validators
Expand Down
12 changes: 12 additions & 0 deletions orm/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ pub mod sql_types {
#[diesel(postgres_type(name = "governance_tally_type"))]
pub struct GovernanceTallyType;

#[derive(
diesel::query_builder::QueryId,
std::fmt::Debug,
diesel::sql_types::SqlType,
)]
#[diesel(postgres_type(name = "validator_state"))]
pub struct ValidatorState;

#[derive(
diesel::query_builder::QueryId,
std::fmt::Debug,
Expand Down Expand Up @@ -139,6 +147,9 @@ diesel::table! {
}

diesel::table! {
use diesel::sql_types::*;
use super::sql_types::ValidatorState;

validators (id) {
id -> Int4,
namada_address -> Varchar,
Expand All @@ -151,6 +162,7 @@ diesel::table! {
description -> Nullable<Varchar>,
discord_handle -> Nullable<Varchar>,
avatar -> Nullable<Varchar>,
state -> ValidatorState,
}
}

Expand Down
33 changes: 29 additions & 4 deletions orm/src/validators.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
use std::str::FromStr;

use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use serde::Serialize;
use shared::validator::Validator;
use diesel::{AsChangeset, Insertable, Queryable, Selectable};
use serde::{Deserialize, Serialize};
use shared::validator::{Validator, ValidatorState};

use crate::schema::validators;

#[derive(Identifiable, Serialize, Queryable, Selectable, Clone, Debug)]
#[derive(Debug, Clone, Serialize, Deserialize, diesel_derive_enum::DbEnum)]
#[ExistingTypePath = "crate::schema::sql_types::ValidatorState"]
pub enum ValidatorStateDb {
Consensus,
BelowCapacity,
BelowThreshold,
Inactive,
Jailed,
Unknown,
}

impl From<ValidatorState> for ValidatorStateDb {
fn from(value: ValidatorState) -> Self {
match value {
ValidatorState::Consensus => Self::Consensus,
ValidatorState::BelowCapacity => Self::BelowCapacity,
ValidatorState::BelowThreshold => Self::BelowThreshold,
ValidatorState::Inactive => Self::Inactive,
ValidatorState::Jailed => Self::Jailed,
ValidatorState::Unknown => Self::Unknown,
}
}
}

#[derive(Serialize, Queryable, Selectable, Clone)]
#[diesel(table_name = validators)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct ValidatorDb {
Expand All @@ -21,6 +45,7 @@ pub struct ValidatorDb {
pub description: Option<String>,
pub discord_handle: Option<String>,
pub avatar: Option<String>,
pub state: ValidatorStateDb,
}

#[derive(Serialize, Insertable, Clone)]
Expand Down
3 changes: 2 additions & 1 deletion pos/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ async fn crawling_fn(
.eq(excluded(validators::columns::max_commission)),
validators::columns::commission
.eq(excluded(validators::columns::commission)),
// TODO: maybe metadata can change more often?
validators::columns::email
.eq(excluded(validators::columns::email)),
validators::columns::website
Expand All @@ -133,6 +132,8 @@ async fn crawling_fn(
.eq(excluded(validators::columns::discord_handle)),
validators::columns::avatar
.eq(excluded(validators::columns::avatar)),
validators::columns::state
.eq(excluded(validators::columns::state)),
))
.execute(transaction_conn)
.context("Failed to update validators in db")?;
Expand Down
19 changes: 16 additions & 3 deletions pos/src/services/namada.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use namada_core::storage::Epoch as NamadaSdkEpoch;
use namada_sdk::rpc;
use shared::block::Epoch;
use shared::id::Id;
use shared::validator::{Validator, ValidatorSet};
use shared::validator::{Validator, ValidatorSet, ValidatorState};
use tendermint_rpc::HttpClient;

pub async fn get_validator_set_at_epoch(
Expand Down Expand Up @@ -47,8 +47,19 @@ pub async fn get_validator_set_at_epoch(
})
};

let (voting_power, commission_pair) =
futures::try_join!(voting_power_fut, commission_fut)?;
let validator_state = async {
rpc::get_validator_state(client, &address, Some(namada_epoch))
.await
.with_context(|| {
format!(
"Failed to query validator {address} \
state"
)
})
};

let (voting_power, commission_pair, validator_state) =
futures::try_join!(voting_power_fut, commission_fut, validator_state)?;
let commission = commission_pair
.commission_rate
.expect("Commission rate has to exist")
Expand All @@ -57,6 +68,7 @@ pub async fn get_validator_set_at_epoch(
.max_commission_change_per_epoch
.expect("Max commission rate change has to exist")
.to_string();
let validator_state = validator_state.0.map(ValidatorState::from).unwrap_or(ValidatorState::Unknown);

anyhow::Ok(Validator {
address: Id::Account(address.to_string()),
Expand All @@ -69,6 +81,7 @@ pub async fn get_validator_set_at_epoch(
website: None,
discord_handler: None,
avatar: None,
state: validator_state
})
})
.buffer_unordered(100)
Expand Down
1 change: 1 addition & 0 deletions shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ futures-util.workspace = true
futures.workspace = true
namada_core.workspace = true
namada_governance.workspace = true
namada_proof_of_stake.workspace = true
namada_ibc.workspace = true
namada_sdk.workspace = true
namada_tx.workspace = true
Expand Down
45 changes: 45 additions & 0 deletions shared/src/validator.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
use fake::faker::company::en::{CatchPhase, CompanyName};
use fake::faker::internet::en::{DomainSuffix, SafeEmail, Username};
use fake::Fake;
use namada_proof_of_stake::types::ValidatorState as NamadaValidatorState;
use rand::distributions::{Distribution, Standard};

use crate::block::Epoch;
use crate::id::Id;

pub type VotingPower = String;

#[derive(Debug, Clone)]
pub enum ValidatorState {
Consensus,
BelowCapacity,
BelowThreshold,
Inactive,
Jailed,
Unknown,
}

impl From<NamadaValidatorState> for ValidatorState {
fn from(value: NamadaValidatorState) -> Self {
match value {
NamadaValidatorState::Consensus => ValidatorState::Consensus,
NamadaValidatorState::BelowCapacity => {
ValidatorState::BelowCapacity
}
NamadaValidatorState::BelowThreshold => {
ValidatorState::BelowThreshold
}
NamadaValidatorState::Inactive => ValidatorState::Inactive,
NamadaValidatorState::Jailed => ValidatorState::Jailed,
}
}
}

#[derive(Debug, Clone)]
pub struct ValidatorSet {
pub validators: Vec<Validator>,
Expand All @@ -25,6 +53,7 @@ pub struct Validator {
pub website: Option<String>,
pub discord_handler: Option<String>,
pub avatar: Option<String>,
pub state: ValidatorState,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -68,6 +97,22 @@ impl Validator {
website,
discord_handler,
avatar: Some("https://picsum.photos/200/300".to_string()),
state: rand::random(),
}
}
}

impl Distribution<ValidatorState> for Standard {
fn sample<R: rand::prelude::Rng + ?Sized>(
&self,
rng: &mut R,
) -> ValidatorState {
match rng.gen_range(0..=5) {
0 => ValidatorState::Consensus,
1 => ValidatorState::Inactive,
2 => ValidatorState::Jailed,
3 => ValidatorState::BelowCapacity,
_ => ValidatorState::BelowThreshold,
}
}
}
43 changes: 43 additions & 0 deletions swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,49 @@ paths:
$ref: '#/components/schemas/Validator'
pagination:
$ref: '#/components/schemas/Pagination'
type: object
properties:
page:
type: integer
minimum: 0
per_page:
type: integer
minimum: 0
total_pages:
type: integer
minimum: 0
total_items:
type: integer
minimum: 0
/api/v1/pos/my-validator:
get:
responses:
'200':
description: Given a list of address return a list of a validator for which those addresses have delegations
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Validator'
pagination:
type: object
properties:
page:
type: integer
minimum: 0
per_page:
type: integer
minimum: 0
total_pages:
type: integer
minimum: 0
total_items:
type: integer
minimum: 0
/api/v1/pos/reward/{address}:
get:
summary: Get all the rewards for an address
Expand Down
4 changes: 4 additions & 0 deletions webserver/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ impl ApplicationServer {

Router::new()
.route("/pos/validator", get(pos_handlers::get_validators))
.route(
"/pos/my-validator",
get(pos_handlers::get_my_validators),
)
.route("/pos/bond/:address", get(pos_handlers::get_bonds))
.route("/pos/unbond/:address", get(pos_handlers::get_unbonds))
.route(
Expand Down
36 changes: 36 additions & 0 deletions webserver/src/dto/pos.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
use serde::{Deserialize, Serialize};
use validator::Validate;

#[derive(Clone, Serialize, Deserialize)]
pub enum ValidatorStateDto {
Consensus,
BelowCapacity,
BelowThreshold,
Inactive,
Jailed,
Unknown,
}

impl ValidatorStateDto {
pub fn all() -> Vec<Self> {
[
Self::Consensus,
Self::BelowCapacity,
Self::BelowThreshold,
Self::Inactive,
Self::Jailed,
Self::Unknown,
]
.to_vec()
}
}

#[derive(Clone, Serialize, Deserialize, Validate)]
pub struct PoSQueryParams {
#[validate(range(min = 1, max = 10000))]
pub page: Option<u64>,
pub state: Option<Vec<ValidatorStateDto>>,
}

#[derive(Clone, Serialize, Deserialize, Validate)]
pub struct MyValidatorQueryParams {
#[validate(range(min = 1, max = 10000))]
pub page: Option<u64>,
#[validate(length(
min = 1,
message = "Address query parameter cannot be empty"
))]
pub addresses: Vec<String>,
}
Loading

0 comments on commit c460ea7

Please sign in to comment.