Building a Validator Analytics Dashboard for CrossFi Using Python: A Comprehensive Guide

JohnJohn
7 min read

Introduction

The CrossFi ecosystem isn’t just about transactions; validators play a pivotal role in maintaining network security and performance. With the CrossFi XFI-Scan API, you can access detailed validator data—such as their status, jailed status, tokens, commission rates, and more. In this guide, we’ll build a validator analytics dashboard using Python. You’ll learn how to query validator data using the official API endpoint, process the JSON output with Pandas, and visualize the information using Matplotlib. Whether you’re a network participant, developer, or node operator, this comprehensive tutorial will help you monitor and analyze validator performance.

API Reference:
Base URL: https://test.xfiscan.com/
Validator
query endpoint: GET /api/1.0/validators
Query parameters include:

  • validatorJailed: Boolean flag indicating if the validator is jailed

  • validatorStatuses: Filter by current status

  • ninAddresses: Array of addresses

  • address/addresses: Specific account addresses

  • page, limit, sort: Pagination and sorting options

For detailed documentation, please refer to the official CrossFi XFI-Scan API docs.


Overview

In this article, we will cover:

  1. Understanding Validator Data:
    We’ll break down the structure of the JSON output for validators, discussing key fields such as the operator address, jailed status, tokens, delegator shares, commission details, and more.

  2. Querying the Validator Endpoint with Python:
    We’ll write Python functions to request validator data using the official API endpoint and query parameters.

  3. Processing Data with Pandas:
    We’ll convert the JSON response into a structured Pandas DataFrame. This allows us to filter, sort, and analyze the data easily.

  4. Visualizing Validator Metrics:
    With Matplotlib, we’ll create visualizations like bar charts and line graphs that show validator token distributions, commission rates, and other key performance metrics.

  5. Building the Dashboard:
    We’ll integrate our code into a unified script that serves as a validator analytics dashboard. Optionally, you can add features like searching or filtering by jailed status or validator status.


Understanding Validator Data

Let’s take a look at a sample JSON output from the validator endpoint:

{
  "docs": [
    {
      "validator": {
        "operator_address": "mxvaloper1qr8rz0cxnasvhzhsdlsd0ndwqdxqlzymyqr2h7",
        "consensus_pubkey": {
          "@type": "/cosmos.crypto.ed25519.PubKey",
          "key": "1l7VMoFylDFUNC/5rbOrTJgQrBKI5DJJ4pF6MlOGeuI="
        },
        "jailed": true,
        "status": "BOND_STATUS_UNBONDED",
        "tokens": "380222155311021111866703",
        "delegator_shares": "391860784639805672563563.302597276497793550",
        "description": {
          "moniker": "htnet farm",
          "identity": "",
          "website": "https://www.htnet.eu",
          "security_contact": "",
          "details": "To"
        },
        "unbonding_height": "2552494",
        "unbonding_time": "2024-04-02T04:50:15.640665631Z",
        "commission": {
          "commission_rates": {
            "rate": "0.050000000000000000",
            "max_rate": "0.050000000000000000",
            "max_change_rate": "0.010000000000000000"
          },
          "update_time": "2024-03-29T13:38:20.425562674Z"
        },
        "min_self_delegation": "1000000",
        "mxAddress": "mx1qr8rz0cxnasvhzhsdlsd0ndwqdxqlzymst65kp",
        "hexAddress": "138e24b8d8268931482d0519560deb43be0bb3ef"
      },
      "active": true,
      "signedBlocks": 2308,
      "unsignedBlocks": 315,
      "delegators_count": "119",
      "unbonding": [
        {
          "denom": "mpx",
          "amount": "0"
        }
      ],
      "unclaimed": [
        {
          "denom": "mpx",
          "amount": "6226191991625290.937382892805759002"
        },
        {
          "denom": "xfi",
          "amount": "153095284270436383.725671145085969640"
        }
      ],
      "start_height": 2447121
    }
    // ... more validator objects
  ]
}

Key Fields Explained:

  • operator_address: Unique identifier for the validator.

  • jailed: Indicates if the validator is currently jailed (locked and unable to validate).

  • status: Shows the bonding status (e.g., BOND_STATUS_UNBONDED).

  • tokens: Total tokens held by the validator.

  • delegator_shares: Reflects the share of delegators.

  • description: Contains human-readable details like the moniker (name), website, and other metadata.

  • commission: Contains the validator’s commission rates and update time.

  • active: A boolean indicating if the validator is active.

  • signedBlocks / unsignedBlocks: Metrics on block signing performance.

  • delegators_count: Number of delegators supporting the validator.

  • unclaimed: Unclaimed rewards for different denominations.

  • start_height: The block height when the validator began operating.

Understanding these fields helps us decide what metrics to track and visualize in our dashboard.


Step 1: Querying the Validator Endpoint with Python

Create a module named xfi_scan_validators.py to query validator data.

import requests

# Base URL for the XFI-Scan API.
BASE_URL = "https://test.xfiscan.com"

def get_validators(limit=10, page=1, sort="-tokens", validatorJailed=None, validatorStatuses=None):
    """
    Fetches validator data from the XFI-Scan API.

    Parameters:
      - limit (number): Number of validators to return.
      - page (number): Pagination page number.
      - sort (string): Field to sort by (e.g., '-tokens' for descending tokens).
      - validatorJailed (boolean, optional): Filter by jailed status.
      - validatorStatuses (string, optional): Filter by validator status.

    Returns:
      A list of validator documents.
    """
    endpoint = f"{BASE_URL}/api/1.0/validators"
    params = {
        "limit": limit,
        "page": page,
        "sort": sort
    }
    if validatorJailed is not None:
        params["validatorJailed"] = str(validatorJailed).lower()
    if validatorStatuses:
        params["validatorStatuses"] = validatorStatuses

    try:
        response = requests.get(endpoint, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()
        # The API returns validator data under the "docs" key.
        return data.get("docs", [])
    except requests.RequestException as e:
        print("Error fetching validators:", e)
        return []

if __name__ == "__main__":
    # Test fetching validators
    validators = get_validators(limit=5)
    for v in validators:
        validator = v.get("validator", {})
        print("Operator Address:", validator.get("operator_address", "N/A"))
        print("Jailed:", validator.get("jailed", "N/A"))
        print("Status:", validator.get("status", "N/A"))
        print("Tokens:", validator.get("tokens", "N/A"))
        print("Moniker:", validator.get("description", {}).get("moniker", "N/A"))
        print("---")

Explanation:

  • We define get_validators to fetch validator data from the endpoint using query parameters like limit, page, and sort.

  • Optional parameters for filtering by jailed status and validator statuses are included.

  • Running this module prints basic details for a few validators.


Step 2: Processing Validator Data with Pandas

Create a file called process_validators.py to convert the JSON data into a structured DataFrame.

import pandas as pd
from xfi_scan_validators import get_validators

def process_validators(validators):
    """
    Converts a list of validator documents into a Pandas DataFrame.
    Extracts key fields such as operator address, jailed status, tokens, 
    status, moniker, signed and unsigned blocks, and delegator count.
    """
    if not validators:
        return pd.DataFrame()

    processed = []
    for doc in validators:
        validator = doc.get("validator", {})
        processed.append({
            "Operator Address": validator.get("operator_address", "N/A"),
            "Jailed": validator.get("jailed", "N/A"),
            "Status": validator.get("status", "N/A"),
            "Tokens": int(validator.get("tokens", 0)),
            "Delegator Shares": validator.get("delegator_shares", "N/A"),
            "Moniker": validator.get("description", {}).get("moniker", "N/A"),
            "Signed Blocks": doc.get("signedBlocks", 0),
            "Unsigned Blocks": doc.get("unsignedBlocks", 0),
            "Delegators Count": int(doc.get("delegators_count", 0))
        })

    df = pd.DataFrame(processed)
    return df

if __name__ == "__main__":
    validators = get_validators(limit=5)
    df_validators = process_validators(validators)
    print("Validators DataFrame:")
    print(df_validators)

Explanation:

  • This script processes each validator document and extracts key fields.

  • The output is a Pandas DataFrame that includes metrics like tokens, jailed status, and performance (signed/unsigned blocks).

  • Running process_validators.py prints the DataFrame.


Step 3: Visualizing Validator Metrics with Matplotlib

Next, create visualize_validators.py to create visualizations.

import matplotlib.pyplot as plt
import pandas as pd
from process_validators import process_validators
from xfi_scan_validators import get_validators

def plot_tokens_distribution(df):
    """
    Plots a bar chart showing the token distribution among validators.
    """
    plt.figure(figsize=(12, 6))
    plt.bar(df["Moniker"], df["Tokens"], color="skyblue")
    plt.title("Validator Token Distribution")
    plt.xlabel("Validator (Moniker)")
    plt.ylabel("Tokens")
    plt.xticks(rotation=45, ha="right")
    plt.tight_layout()
    plt.show()

def plot_validator_performance(df):
    """
    Plots a line chart comparing signed and unsigned blocks for each validator.
    """
    plt.figure(figsize=(12, 6))
    plt.plot(df["Moniker"], df["Signed Blocks"], marker="o", label="Signed Blocks")
    plt.plot(df["Moniker"], df["Unsigned Blocks"], marker="x", label="Unsigned Blocks", linestyle="--")
    plt.title("Validator Block Signing Performance")
    plt.xlabel("Validator (Moniker)")
    plt.ylabel("Blocks")
    plt.xticks(rotation=45, ha="right")
    plt.legend()
    plt.tight_layout()
    plt.show()

if __name__ == "__main__":
    validators = get_validators(limit=10)
    df_validators = process_validators(validators)
    plot_tokens_distribution(df_validators)
    plot_validator_performance(df_validators)

Explanation:

  • plot_tokens_distribution visualizes the token holdings of each validator.

  • plot_validator_performance compares signed vs. unsigned blocks, providing insight into validator reliability.

  • Running visualize_validators.py displays these charts.


Step 4: Building the Unified Validator Dashboard

Now, integrate everything into a single script named dashboard_validators.py.

from xfi_scan_validators import get_validators, search_validators
from process_validators import process_validators
from visualize_validators import plot_tokens_distribution, plot_validator_performance

def main():
    print("Fetching validator data from the XFI-Scan API...")
    validators = get_validators(limit=10, sort="-tokens")

    # Process validator data into a DataFrame.
    df_validators = process_validators(validators)

    if df_validators.empty:
        print("No validator data available.")
    else:
        print("Validator Data:")
        print(df_validators)

        # Visualize token distribution and performance.
        plot_tokens_distribution(df_validators)
        plot_validator_performance(df_validators)

    # Optional: Search for validators based on specific criteria.
    search_input = input("Enter a validator operator address to search (or press Enter to skip): ")
    if search_input:
        # (Assuming search_validators is implemented similarly to search_transactions.)
        searched_validators = search_validators(search_input)
        df_search = process_validators(searched_validators)
        print("Search Results:")
        print(df_search)
        plot_tokens_distribution(df_search)
        plot_validator_performance(df_search)

if __name__ == "__main__":
    main()

Note:
If you need a search_validators function, you can implement it by adding an appropriate parameter (e.g., filtering by address).

Explanation:

  • dashboard_validators.py is the entry point for our validator analytics dashboard.

  • It fetches validator data, processes it into a DataFrame, prints the results, and then visualizes the token distribution and performance metrics.

  • An optional search feature allows filtering validators by operator address.


Conclusion

In this comprehensive guide, we built a Validator Analytics Dashboard for the CrossFi ecosystem using Python. We covered:

  • API Integration:
    We used the official validator endpoint (GET /api/1.0/validators on https://test.xfiscan.com/) to retrieve validator data.

  • Data Processing:
    With process_validators.py, we extracted key fields such as operator address, jailed status, tokens, and performance metrics, converting the JSON output into a Pandas DataFrame.

  • Visualization:
    Using Matplotlib, we created visualizations to display the token distribution and block signing performance of validators.

  • Dashboard Assembly:
    Finally, we integrated these components into dashboard_validators.py, offering a unified tool to monitor and analyze validator performance in real-time.

This project provides a solid foundation for further expansion. Future enhancements might include real-time data updates, additional filtering options, or even a web-based dashboard using frameworks like Flask or Django. With these tools at your disposal, you’re well on your way to mastering validator analytics in the CrossFi ecosystem.

Happy coding, and may your validators always perform at their peak!

0
Subscribe to my newsletter

Read articles from John directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

John
John