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

Add network metrics endpoint #2143

Merged
merged 15 commits into from
Mar 8, 2024
9 changes: 4 additions & 5 deletions .github/actions/private-tangle/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ runs:
uses: actions/checkout@v3
with:
repository: iotaledger/iota-core
# TODO: remove ref when inx plugins are updated to the latest commit
ref: 25995c84ccc4f4cd9041881035f338acca513b0a
path: iota-core

- name: Prepare files for start and stop
Expand Down Expand Up @@ -40,6 +38,7 @@ runs:
- name: Wait for tangle to start
shell: bash
run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/v2.2.4/wait-for | sh -s -- -t 120 http://localhost:8050/health -- echo "Tangle is up"
- name: Wait for faucet to start
shell: bash
run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/v2.2.4/wait-for | sh -s -- -t 120 http://localhost:8088/health -- echo "Faucet is up"
# TODO https://github.com/iotaledger/iota-sdk/issues/2154
# - name: Wait for faucet to start
DaughterOfMars marked this conversation as resolved.
Show resolved Hide resolved
# shell: bash
# run: wget -qO- https://raw.githubusercontent.com/eficode/wait-for/v2.2.4/wait-for | sh -s -- -t 120 http://localhost:8088/health -- echo "Faucet is up"
2 changes: 2 additions & 0 deletions bindings/core/src/method/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ pub enum ClientMethod {
},
/// Returns general information about the node together with its URL.
GetNodeInfo,
/// Returns network metrics.
GetNetworkMetrics,
/// Check the readiness of the node to issue a new block, the reference mana cost based on the rate setter and
/// current network congestion, and the block issuance credits of the requested account.
#[serde(rename_all = "camelCase")]
Expand Down
1 change: 1 addition & 0 deletions bindings/core/src/method_handler/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ pub(crate) async fn call_client_method_internal(
ClientMethod::GetHealth { url } => Response::Bool(client.get_health(&url).await?),
ClientMethod::GetInfo { url, auth } => Response::Info(Client::get_info(&url, auth).await?),
ClientMethod::GetNodeInfo => Response::NodeInfo(client.get_node_info().await?),
ClientMethod::GetNetworkMetrics => Response::NetworkMetrics(client.get_network_metrics().await?),
ClientMethod::GetRoutes => Response::Routes(client.get_routes().await?),
ClientMethod::GetAccountCongestion { account_id, work_score } => {
Response::Congestion(client.get_account_congestion(&account_id, work_score).await?)
Expand Down
9 changes: 6 additions & 3 deletions bindings/core/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use iota_sdk::{
api::{
core::{
BlockMetadataResponse, BlockWithMetadataResponse, CommitteeResponse, CongestionResponse, InfoResponse,
IssuanceBlockHeaderResponse, ManaRewardsResponse, OutputResponse, OutputWithMetadataResponse,
RoutesResponse, TransactionMetadataResponse, UtxoChangesFullResponse, UtxoChangesResponse,
ValidatorResponse, ValidatorsResponse,
IssuanceBlockHeaderResponse, ManaRewardsResponse, NetworkMetricsResponse, OutputResponse,
OutputWithMetadataResponse, RoutesResponse, TransactionMetadataResponse, UtxoChangesFullResponse,
UtxoChangesResponse, ValidatorResponse, ValidatorsResponse,
},
plugins::indexer::OutputIdsResponse,
},
Expand Down Expand Up @@ -102,6 +102,9 @@ pub enum Response {
/// - [`GetNodeInfo`](crate::method::ClientMethod::GetNodeInfo)
NodeInfo(NodeInfoResponse),
/// Response for:
/// - [`GetNetworkMetrics`](crate::method::ClientMethod::GetNetworkMetrics)
NetworkMetrics(NetworkMetricsResponse),
/// Response for:
/// - [`GetRoutes`](crate::method::ClientMethod::GetRoutes)
Routes(RoutesResponse),
/// Response for:
Expand Down
12 changes: 12 additions & 0 deletions bindings/nodejs/lib/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {
IssuanceBlockHeaderResponse,
OutputMetadataResponse,
OutputWithMetadataResponse,
NetworkMetricsResponse,
} from '../types/models/api';
import { RoutesResponse } from '../types/models/api/routes-response';

Expand Down Expand Up @@ -156,6 +157,17 @@ export class Client {
return JSON.parse(response).payload;
}

/**
* Get the network metrics.
*/
async getNetworkMetrics(): Promise<NetworkMetricsResponse> {
const response = await this.methodHandler.callMethod({
name: 'getNetworkMetrics',
});

return JSON.parse(response).payload;
}

// Accounts routes.

/**
Expand Down
4 changes: 4 additions & 0 deletions bindings/nodejs/lib/types/client/bridge/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ export interface __GetInfoMethod__ {
};
}

export interface __GetNetworkMetricsMethod__ {
name: 'getNetworkMetrics';
}

// Accounts routes.

export interface __GetAccountCongestionMethod__ {
Expand Down
2 changes: 2 additions & 0 deletions bindings/nodejs/lib/types/client/bridge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
__GetProtocolParametersMethod__,
__GetHealthMethod__,
__GetNodeInfoMethod__,
__GetNetworkMetricsMethod__,
__GetBlockRawMethod__,
__GetIncludedBlockMethod__,
__GetIncludedBlockRawMethod__,
Expand Down Expand Up @@ -102,6 +103,7 @@ export type __ClientMethods__ =
| __GetProtocolParametersMethod__
| __GetHealthMethod__
| __GetNodeInfoMethod__
| __GetNetworkMetricsMethod__
| __GetBlockRawMethod__
| __GetIncludedBlockMethod__
| __GetIncludedBlockRawMethod__
Expand Down
1 change: 1 addition & 0 deletions bindings/nodejs/lib/types/models/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './committee-response';
export * from './congestion-response';
export * from './issuance-response';
export * from './mana-rewards-response';
export * from './network-metrics';
export * from './output-id-proof';
export * from './output-metadata-response';
export * from './output-response';
Expand Down
1 change: 0 additions & 1 deletion bindings/nodejs/lib/types/models/api/info/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@

export * from './node-info';
export * from './node-info-base-token';
export * from './node-info-metrics';
export * from './node-info-protocol';
export * from './node-info-status';
5 changes: 0 additions & 5 deletions bindings/nodejs/lib/types/models/api/info/node-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

import type { BaseTokenResponse } from './node-info-base-token';
import type { MetricsResponse } from './node-info-metrics';
import type { ProtocolParametersResponse } from './node-info-protocol';
import type { StatusResponse } from './node-info-status';
/**
Expand All @@ -21,10 +20,6 @@ export interface InfoResponse {
* The status of the node.
*/
status: StatusResponse;
/**
* The metrics for the node.
*/
metrics: MetricsResponse;
/**
* The protocol parameters.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright 2023 IOTA Stiftung
// Copyright 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

/**
* Response from the /info endpoint.
* Metrics information about the network.
*/
export interface MetricsResponse {
export interface NetworkMetricsResponse {
/**
* The current rate of new blocks per second.
*/
Expand Down
21 changes: 17 additions & 4 deletions bindings/python/iota_sdk/client/_node_core_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from typing import List, Optional, Union
from abc import ABCMeta, abstractmethod
from iota_sdk.client.responses import InfoResponse, NodeInfoResponse, RoutesResponse, CongestionResponse, ManaRewardsResponse, CommitteeResponse, ValidatorResponse, ValidatorsResponse, IssuanceBlockHeaderResponse, BlockMetadataResponse, BlockWithMetadataResponse, OutputResponse, OutputWithMetadataResponse, TransactionMetadataResponse, UtxoChangesResponse, UtxoChangesFullResponse
from iota_sdk.client.responses import InfoResponse, NodeInfoResponse, NetworkMetricsResponse, RoutesResponse, CongestionResponse, ManaRewardsResponse, CommitteeResponse, ValidatorResponse, ValidatorsResponse, IssuanceBlockHeaderResponse, BlockMetadataResponse, BlockWithMetadataResponse, OutputResponse, OutputWithMetadataResponse, TransactionMetadataResponse, UtxoChangesResponse, UtxoChangesFullResponse
from iota_sdk.types.block.block import Block
from iota_sdk.types.block.id import BlockId
from iota_sdk.types.common import HexStr, EpochIndex, SlotIndex
Expand Down Expand Up @@ -82,9 +82,20 @@ def get_info(self, url: str, auth=None) -> InfoResponse:
'auth': auth
}))

def get_network_metrics(self) -> NetworkMetricsResponse:
"""Returns network metrics.
GET /api/core/v3/network/metrics

Returns:
Network metrics.
"""
return NetworkMetricsResponse.from_dict(
self._call_method('getNetworkMetrics'))

# Accounts routes.

def get_account_congestion(self, account_id: HexStr, work_score: Optional[int] = None) -> CongestionResponse:
def get_account_congestion(
self, account_id: HexStr, work_score: Optional[int] = None) -> CongestionResponse:
"""Checks if the account is ready to issue a block.
GET /api/core/v3/accounts/{bech32Address}/congestion
"""
Expand Down Expand Up @@ -112,7 +123,8 @@ def get_output_mana_rewards(

# Validators routes.

def get_validators(self, page_size: Optional[int] = None, cursor: Optional[str] = None) -> ValidatorsResponse:
def get_validators(
self, page_size: Optional[int] = None, cursor: Optional[str] = None) -> ValidatorsResponse:
"""Returns information of all stakers (registered validators) and if they are active, ordered by their holding stake.
GET /api/core/v3/validators
"""
Expand All @@ -131,7 +143,8 @@ def get_validator(self, account_id: HexStr) -> ValidatorResponse:

# Committee routes.

def get_committee(self, epoch_index: Optional[EpochIndex] = None) -> CommitteeResponse:
def get_committee(
self, epoch_index: Optional[EpochIndex] = None) -> CommitteeResponse:
"""Returns the information of committee members at the given epoch index. If epoch index is not provided, the
current committee members are returned.
GET /api/core/v3/committee/?epochIndex
Expand Down
3 changes: 2 additions & 1 deletion bindings/python/iota_sdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ def get_node(self) -> Dict[str, Any]:
def get_protocol_parameters(self) -> ProtocolParameters:
"""Gets the protocol parameters.
"""
return ProtocolParameters.from_dict(self._call_method('getProtocolParameters'))
return ProtocolParameters.from_dict(
self._call_method('getProtocolParameters'))

def get_network_id(self) -> int:
"""Gets the network id of the node we're connecting to.
Expand Down
25 changes: 22 additions & 3 deletions bindings/python/iota_sdk/client/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from iota_sdk.types.block.block import Block
from iota_sdk.types.block.id import BlockId
from iota_sdk.types.common import HexStr, json, EpochIndex, SlotIndex
from iota_sdk.types.node_info import BaseTokenResponse, MetricsResponse, StatusResponse, ProtocolParameters
from iota_sdk.types.node_info import BaseTokenResponse, StatusResponse, ProtocolParameters
from iota_sdk.types.output import Output, deserialize_output
from iota_sdk.types.output_id import OutputId, OutputWithId
from iota_sdk.types.output_id_proof import OutputIdProof
Expand Down Expand Up @@ -56,14 +56,12 @@ class InfoResponse:
name: The name of the node (e.g. Hornet).
version: The semantic version of the node.
status: The status of the node.
metrics: Node metrics.
protocol_parameters: Supported protocol versions by the node.
base_token: Gives info about the base token the network uses.
"""
name: str
version: str
status: StatusResponse
metrics: MetricsResponse
protocol_parameters: List[ProtocolParametersResponse]
base_token: BaseTokenResponse

Expand All @@ -82,8 +80,29 @@ class NodeInfoResponse:
url: str


@json
@dataclass
class NetworkMetricsResponse:
"""Network metrics.

Attributes:
blocks_per_second: The current rate of new blocks per second.
confirmed_blocks_per_second: The current rate of confirmed blocks per second.
confirmation_rate: The ratio of confirmed blocks to new blocks of the last confirmed slot.
"""
blocks_per_second: float = field(metadata=config(
encoder=str
))
confirmed_blocks_per_second: float = field(metadata=config(
encoder=str
))
confirmation_rate: float = field(metadata=config(
encoder=str
))

# Accounts routes responses


@json
@dataclass
class CongestionResponse:
Expand Down
21 changes: 0 additions & 21 deletions bindings/python/iota_sdk/types/node_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,6 @@ class StatusResponse:
pruning_epoch: EpochIndex


@json
@dataclass
class MetricsResponse:
"""Node metrics.

Attributes:
blocks_per_second: The current rate of new blocks per second.
confirmed_blocks_per_second: The current rate of confirmed blocks per second.
confirmation_rate: The ratio of confirmed blocks to new blocks of the last confirmed slot.
"""
blocks_per_second: float = field(metadata=config(
encoder=str
))
confirmed_blocks_per_second: float = field(metadata=config(
encoder=str
))
confirmation_rate: float = field(metadata=config(
encoder=str
))


@json
@dataclass
class StorageScoreParameters:
Expand Down
5 changes: 3 additions & 2 deletions bindings/python/tests/test_api_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from typing import Generic, TypeVar
from json import load, loads, dumps
from iota_sdk import RoutesResponse, CongestionResponse, OutputWithMetadataResponse, ManaRewardsResponse, ValidatorsResponse, ValidatorResponse, InfoResponse, CommitteeResponse, IssuanceBlockHeaderResponse, Block, BlockMetadataResponse, BlockWithMetadataResponse, OutputMetadata, OutputResponse, TransactionMetadataResponse, SlotCommitment, UtxoChangesResponse, UtxoChangesFullResponse
from iota_sdk import RoutesResponse, CongestionResponse, OutputWithMetadataResponse, ManaRewardsResponse, ValidatorsResponse, ValidatorResponse, CommitteeResponse, IssuanceBlockHeaderResponse, Block, BlockMetadataResponse, BlockWithMetadataResponse, OutputMetadata, OutputResponse, TransactionMetadataResponse, SlotCommitment, UtxoChangesResponse, UtxoChangesFullResponse


base_path = '../../sdk/tests/types/api/fixtures/'
Expand All @@ -27,7 +27,8 @@ def test_api_response(cls_type: Generic[T], path: str):
# GET /api/routes
test_api_response(RoutesResponse, "get-routes-response-example.json")
# GET /api/core/v3/info
test_api_response(InfoResponse, "get-info-response-example.json")
# TODO reenable when Metrics are split out of Info
# test_api_response(InfoResponse, "get-info-response-example.json")
# GET /api/core/v3/accounts/{bech32Address}/congestion
test_api_response(CongestionResponse,
"get-congestion-estimate-response-example.json")
Expand Down
15 changes: 12 additions & 3 deletions sdk/src/client/node_api/core/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ use crate::{
types::{
api::core::{
BlockMetadataResponse, BlockWithMetadataResponse, CommitteeResponse, CongestionResponse, InfoResponse,
IssuanceBlockHeaderResponse, ManaRewardsResponse, OutputResponse, OutputWithMetadataResponse,
PermanodeInfoResponse, RoutesResponse, SubmitBlockResponse, TransactionMetadataResponse,
UtxoChangesFullResponse, UtxoChangesResponse, ValidatorResponse, ValidatorsResponse,
IssuanceBlockHeaderResponse, ManaRewardsResponse, NetworkMetricsResponse, OutputResponse,
OutputWithMetadataResponse, PermanodeInfoResponse, RoutesResponse, SubmitBlockResponse,
TransactionMetadataResponse, UtxoChangesFullResponse, UtxoChangesResponse, ValidatorResponse,
ValidatorsResponse,
},
block::{
address::ToBech32Ext,
Expand Down Expand Up @@ -87,6 +88,14 @@ impl ClientInner {
pub async fn get_node_info(&self) -> Result<NodeInfoResponse, ClientError> {
self.get_request(INFO_PATH, None, false).await
}

/// Returns network metrics.
/// GET /api/core/v3/network/metrics
pub async fn get_network_metrics(&self) -> Result<NetworkMetricsResponse, ClientError> {
const PATH: &str = "api/core/v3/network/metrics";

self.get_request(PATH, None, false).await
}
}

impl Client {
Expand Down
6 changes: 2 additions & 4 deletions sdk/src/types/api/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ pub struct InfoResponse {
pub name: String,
pub version: String,
pub status: StatusResponse,
pub metrics: MetricsResponse,
pub protocol_parameters: ProtocolParametersMap,
pub base_token: BaseTokenResponse,
}
Expand Down Expand Up @@ -105,11 +104,10 @@ pub struct StatusResponse {
pub pruning_epoch: EpochIndex,
}

/// Returned in [`InfoResponse`].
/// Metric information about the node.
/// Metrics information about the network.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MetricsResponse {
pub struct NetworkMetricsResponse {
#[serde(with = "string")]
pub blocks_per_second: f64,
#[serde(with = "string")]
Expand Down
3 changes: 2 additions & 1 deletion sdk/tests/types/api/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ fn responses() {
// GET /api/routes
json_response::<RoutesResponse>("get-routes-response-example.json").unwrap();
// GET /api/core/v3/info
json_response::<InfoResponse>("get-info-response-example.json").unwrap();
// TODO reenable when Metrics are split out of Info
// json_response::<InfoResponse>("get-info-response-example.json").unwrap();
// GET /api/core/v3/accounts/{bech32Address}/congestion
json_response::<CongestionResponse>("get-congestion-estimate-response-example.json").unwrap();
// GET /api/core/v3/rewards/{outputId}
Expand Down
Loading