iota_rosetta/
network.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5//! This module implements the [Rosetta Network API](https://www.rosetta-api.org/docs/NetworkApi.html).
6
7use axum::{Extension, Json, extract::State};
8use axum_extra::extract::WithRejection;
9use fastcrypto::encoding::Hex;
10use iota_types::base_types::ObjectID;
11use serde_json::json;
12use strum::IntoEnumIterator;
13
14use crate::{
15    IotaEnv, OnlineServerContext,
16    errors::{Error, ErrorType},
17    types::{
18        Allow, Case, NetworkIdentifier, NetworkListResponse, NetworkOptionsResponse,
19        NetworkRequest, NetworkStatusResponse, OperationStatus, OperationType, Peer, SyncStatus,
20        Version,
21    },
22};
23
24/// This endpoint returns a list of NetworkIdentifiers that the Rosetta server
25/// supports.
26///
27/// [Rosetta API Spec](https://www.rosetta-api.org/docs/NetworkApi.html#networklist)
28pub async fn list(Extension(env): Extension<IotaEnv>) -> Result<NetworkListResponse, Error> {
29    Ok(NetworkListResponse {
30        network_identifiers: vec![NetworkIdentifier {
31            blockchain: "iota".to_string(),
32            network: env,
33        }],
34    })
35}
36
37/// This endpoint returns the current status of the network requested.
38///
39/// [Rosetta API Spec](https://www.rosetta-api.org/docs/NetworkApi.html#networkstatus)
40pub async fn status(
41    State(context): State<OnlineServerContext>,
42    Extension(env): Extension<IotaEnv>,
43    WithRejection(Json(request), _): WithRejection<Json<NetworkRequest>, Error>,
44) -> Result<NetworkStatusResponse, Error> {
45    env.check_network_identifier(&request.network_identifier)?;
46
47    // We get the public_key and stake_amount of all committee members.
48    let peers = context
49        .client
50        .governance_api()
51        .get_latest_iota_system_state()
52        .await?
53        .iter_committee_members()
54        .map(|committee_member| Peer {
55            peer_id: ObjectID::from(committee_member.iota_address).into(),
56            metadata: Some(json!({
57                "public_key": Hex::from_bytes(&committee_member.authority_pubkey_bytes),
58                "stake_amount": committee_member.staking_pool_iota_balance,
59            })),
60        })
61        .collect();
62    let blocks = context.blocks();
63    let current_block = blocks.current_block().await?;
64    let index = current_block.block.block_identifier.index;
65    let target = context
66        .client
67        .read_api()
68        .get_latest_checkpoint_sequence_number()
69        .await?;
70
71    Ok(NetworkStatusResponse {
72        current_block_identifier: current_block.block.block_identifier,
73        current_block_timestamp: current_block.block.timestamp,
74        genesis_block_identifier: blocks.genesis_block_identifier().await?,
75        oldest_block_identifier: Some(blocks.oldest_block_identifier().await?),
76        sync_status: Some(SyncStatus {
77            current_index: Some(index),
78            target_index: Some(target),
79            stage: None,
80            synced: Some(index == target),
81        }),
82        peers,
83    })
84}
85
86/// This endpoint returns the version information and allowed network-specific
87/// types for a NetworkIdentifier.
88///
89/// [Rosetta API Spec](https://www.rosetta-api.org/docs/NetworkApi.html#networkoptions)
90pub async fn options(
91    Extension(env): Extension<IotaEnv>,
92    WithRejection(Json(request), _): WithRejection<Json<NetworkRequest>, Error>,
93) -> Result<NetworkOptionsResponse, Error> {
94    env.check_network_identifier(&request.network_identifier)?;
95
96    let errors = ErrorType::iter().collect();
97    let operation_statuses = vec![
98        json!({"status": OperationStatus::Success, "successful" : true}),
99        json!({"status": OperationStatus::Failure, "successful" : false}),
100    ];
101
102    Ok(NetworkOptionsResponse {
103        version: Version {
104            rosetta_version: "1.4.14".to_string(),
105            node_version: env!("CARGO_PKG_VERSION").to_owned(),
106            middleware_version: None,
107            metadata: None,
108        },
109        allow: Allow {
110            operation_statuses,
111            operation_types: OperationType::iter().collect(),
112            errors,
113            historical_balance_lookup: true,
114            timestamp_start_index: None,
115            call_methods: vec![],
116            balance_exemptions: vec![],
117            mempool_coins: false,
118            block_hash_case: Some(Case::Null),
119            transaction_hash_case: Some(Case::Null),
120        },
121    })
122}