Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Index token supplies #268

Merged
merged 13 commits into from
Feb 7, 2025
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namada_ibc = { git = "https://github.com/anoma/namada", tag = "libs-v0.47.0" }
namada_token = { git = "https://github.com/anoma/namada", tag = "libs-v0.47.0" }
namada_parameters = { git = "https://github.com/anoma/namada", tag = "libs-v0.47.0" }
namada_proof_of_stake = { git = "https://github.com/anoma/namada", tag = "libs-v0.47.0" }
num-bigint = "0.4.6"
tendermint = "0.38.0"
tendermint-config = "0.38.0"
tendermint-rpc = { version = "0.38.0", features = ["http-client"] }
Expand Down
16 changes: 16 additions & 0 deletions chain/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use shared::checksums::Checksums;
use shared::crawler::crawl;
use shared::crawler_state::ChainCrawlerState;
use shared::error::{AsDbError, AsRpcError, ContextDbInteractError, MainError};
use shared::futures::AwaitContainer;
use shared::id::Id;
use shared::token::Token;
use shared::utils::BalanceChange;
Expand Down Expand Up @@ -235,6 +236,16 @@ async fn crawling_fn(
));
let addresses = block.addresses_with_balance_change(&native_token);

let native_token_supplies = first_block_in_epoch
.eq(&block_height)
.then(|| {
namada_service::get_token_supplies(&client, &native_token, epoch)
})
.future()
.await
.transpose()
.into_rpc_error()?;

let validators_addresses = if first_block_in_epoch.eq(&block_height) {
namada_service::get_all_consensus_validators_addresses_at(
&client,
Expand Down Expand Up @@ -411,6 +422,11 @@ async fn crawling_fn(
ibc_tokens,
)?;

repository::balance::insert_token_supplies(
transaction_conn,
native_token_supplies,
)?;

repository::block::upsert_block(
transaction_conn,
block,
Expand Down
34 changes: 32 additions & 2 deletions chain/src/repository/balance.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use anyhow::Context;
use diesel::{PgConnection, RunQueryDsl};
use orm::balances::BalanceChangesInsertDb;
use orm::schema::{balance_changes, ibc_token, token};
use orm::schema::{
balance_changes, ibc_token, token, token_supplies_per_epoch,
};
use orm::token::{IbcTokenInsertDb, TokenInsertDb};
use shared::balance::Balances;
use orm::token_supplies_per_epoch::TokenSuppliesInsertDb;
use shared::balance::{Balances, TokenSupply};
use shared::token::Token;
use shared::tuple_len::TupleLen;

Expand Down Expand Up @@ -70,6 +73,33 @@ pub fn insert_tokens(
anyhow::Ok(())
}

pub fn insert_token_supplies<S>(
transaction_conn: &mut PgConnection,
supplies: S,
) -> anyhow::Result<()>
where
S: IntoIterator<Item = TokenSupply>,
{
let supplies: Vec<_> = supplies
.into_iter()
.map(TokenSuppliesInsertDb::from)
.collect();

if supplies.is_empty() {
return anyhow::Ok(());
}

tracing::debug!(?supplies, "Adding new token supplies to db");

diesel::insert_into(token_supplies_per_epoch::table)
.values(supplies)
.on_conflict_do_nothing()
.execute(transaction_conn)
.context("Failed to update token supplies in db")?;

anyhow::Ok(())
}

#[cfg(test)]
mod tests {

Expand Down
46 changes: 45 additions & 1 deletion chain/src/services/namada.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use namada_sdk::rpc::{
use namada_sdk::state::Key;
use namada_sdk::token::Amount as NamadaSdkAmount;
use namada_sdk::{borsh, rpc, token};
use shared::balance::{Amount, Balance, Balances};
use shared::balance::{Amount, Balance, Balances, TokenSupply};
use shared::block::{BlockHeight, Epoch};
use shared::bond::{Bond, BondAddresses, Bonds};
use shared::id::Id;
Expand All @@ -42,6 +42,30 @@ pub async fn get_native_token(client: &HttpClient) -> anyhow::Result<Id> {
Ok(Id::from(native_token))
}

pub async fn query_native_token_total_supply(
client: &HttpClient,
) -> anyhow::Result<Amount> {
let native_token = RPC
.shell()
.native_token(client)
.await
.context("Failed to query native token")?;

rpc::get_token_total_supply(client, &native_token)
.await
.map(Amount::from)
.context("Failed to query total supply of native token")
}

pub async fn query_native_token_effective_supply(
client: &HttpClient,
) -> anyhow::Result<Amount> {
rpc::get_effective_native_supply(client)
.await
.map(Amount::from)
.context("Failed to query effective supply of native token")
}

pub async fn get_first_block_in_epoch(
client: &HttpClient,
) -> anyhow::Result<BlockHeight> {
Expand Down Expand Up @@ -797,3 +821,23 @@ pub async fn get_pgf_receipients(
})
.collect::<HashSet<_>>()
}

pub async fn get_token_supplies(
client: &HttpClient,
native_token: &Id,
epoch: u32,
) -> anyhow::Result<TokenSupply> {
let total_supply_fut = query_native_token_total_supply(client);
let effective_supply_fut = query_native_token_effective_supply(client);

let (total_supply, effective_supply) =
futures::try_join!(total_supply_fut, effective_supply_fut)
.context("Failed to query native token supplies")?;

anyhow::Ok(TokenSupply {
address: native_token.to_string(),
epoch: epoch as _,
total: total_supply.into(),
effective: Some(effective_supply.into()),
})
}
4 changes: 2 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ toolchains:
@echo {{ RUST_STABLE }}
@echo {{ RUST_NIGTHLY }}

build:
cargo +{{ RUST_STABLE }} build --all
build *BIN:
cargo +{{ RUST_STABLE }} build {{ if BIN != "" { prepend("--bin ", BIN) } else { "--all" } }}

check:
cargo +{{ RUST_STABLE }} check --all
Expand Down
11 changes: 11 additions & 0 deletions orm/migrations/2025-02-06-093718_token_supplies/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- This file should undo anything in `up.sql`

-- Drop the foreign key constraint on the address column
ALTER TABLE token_supplies_per_epoch
DROP CONSTRAINT fk_token_supplies_per_epoch_address;

-- Drop the trigger for enforcing the effective constraint
DROP TRIGGER enforce_effective_constraint ON token_supplies_per_epoch;

-- Drop the table itself
DROP TABLE token_supplies_per_epoch;
39 changes: 39 additions & 0 deletions orm/migrations/2025-02-06-093718_token_supplies/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
-- Your SQL goes here

CREATE TABLE token_supplies_per_epoch (
id SERIAL PRIMARY KEY,
address VARCHAR(45) NOT NULL,
epoch INT NOT NULL,
-- `2^256 - 1` will fit in `NUMERIC(78, 0)`
total NUMERIC(78, 0) NOT NULL,
effective NUMERIC(78, 0),
-- reference the `address` column in the `token` table
CONSTRAINT fk_token_supplies_per_epoch_address
FOREIGN KEY(address) REFERENCES token(address) ON DELETE CASCADE
);

ALTER TABLE token_supplies_per_epoch ADD UNIQUE (address, epoch);

CREATE OR REPLACE FUNCTION check_effective_for_token_type()
RETURNS TRIGGER AS $$
BEGIN
-- Check if the referenced token_type is 'native'
IF EXISTS (
SELECT 1
FROM token
WHERE token.address = NEW.address AND token.token_type = 'native'
) THEN
-- If token_type is 'native', ensure token_supplies_per_epoch.effective is not NULL
IF NEW.effective IS NULL THEN
RAISE EXCEPTION 'token_supplies_per_epoch.effective cannot be NULL when token.token_type is ''native''';
END IF;
END IF;
-- Allow the insert or update to proceed
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER enforce_effective_constraint
BEFORE INSERT OR UPDATE ON token_supplies_per_epoch
FOR EACH ROW
EXECUTE FUNCTION check_effective_for_token_type();
1 change: 1 addition & 0 deletions orm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod pos_rewards;
pub mod revealed_pk;
pub mod schema;
pub mod token;
pub mod token_supplies_per_epoch;
pub mod transactions;
pub mod unbond;
pub mod validators;
Expand Down
13 changes: 13 additions & 0 deletions orm/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,17 @@ diesel::table! {
}
}

diesel::table! {
token_supplies_per_epoch (id) {
id -> Int4,
#[max_length = 45]
address -> Varchar,
epoch -> Int4,
total -> Numeric,
effective -> Nullable<Numeric>,
}
}

diesel::table! {
use diesel::sql_types::*;
use super::sql_types::HistoryKind;
Expand Down Expand Up @@ -397,6 +408,7 @@ diesel::joinable!(ibc_token -> token (address));
diesel::joinable!(inner_transactions -> wrapper_transactions (wrapper_id));
diesel::joinable!(pos_rewards -> validators (validator_id));
diesel::joinable!(public_good_funding -> governance_proposals (proposal_id));
diesel::joinable!(token_supplies_per_epoch -> token (address));
diesel::joinable!(transaction_history -> inner_transactions (inner_tx_id));
diesel::joinable!(unbonds -> validators (validator_id));
diesel::joinable!(wrapper_transactions -> blocks (block_height));
Expand All @@ -419,6 +431,7 @@ diesel::allow_tables_to_appear_in_same_query!(
public_good_funding,
revealed_pk,
token,
token_supplies_per_epoch,
transaction_history,
unbonds,
validators,
Expand Down
44 changes: 44 additions & 0 deletions orm/src/token_supplies_per_epoch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use bigdecimal::BigDecimal;
use diesel::{Insertable, Queryable, Selectable};
use shared::balance::TokenSupply as SharedTokenSupply;

use crate::schema::token_supplies_per_epoch;

#[derive(Debug, Clone, Queryable, Selectable)]
#[diesel(table_name = token_supplies_per_epoch)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct TokenSuppliesDb {
pub id: i32,
pub address: String,
pub epoch: i32,
pub total: BigDecimal,
pub effective: Option<BigDecimal>,
}

#[derive(Debug, Clone, Queryable, Selectable, Insertable)]
#[diesel(table_name = token_supplies_per_epoch)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct TokenSuppliesInsertDb {
pub address: String,
pub epoch: i32,
pub total: BigDecimal,
pub effective: Option<BigDecimal>,
}

impl From<SharedTokenSupply> for TokenSuppliesInsertDb {
fn from(supply: SharedTokenSupply) -> Self {
let SharedTokenSupply {
address,
epoch,
total,
effective,
} = supply;

Self {
address,
epoch,
total,
effective,
}
}
}
3 changes: 2 additions & 1 deletion shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namada_proof_of_stake.workspace = true
namada_ibc.workspace = true
namada_sdk.workspace = true
namada_tx.workspace = true
num-bigint.workspace = true
serde.workspace = true
serde_json.workspace = true
subtle-encoding.workspace = true
Expand All @@ -39,4 +40,4 @@ tokio.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
fake.workspace = true
rand.workspace = true
rand.workspace = true
Loading