From 3e7a03884e9a964757f89adb306e33782b5919df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Volek?= Date: Wed, 15 Jul 2026 22:58:34 +0200 Subject: [PATCH] fix: remove api prefix --- CHANGELOG.md | 1 + crates/integration_tests/src/gateway/mod.rs | 17 +- crates/integration_tests/src/platform/mod.rs | 7 +- .../integration_tests/tests/e2e_websocket.rs | 4 +- .../tests/platform_data_node.rs | 6 +- .../tests/platform_metrics.rs | 2 +- .../integration_tests/tests/platform_root.rs | 2 +- .../tests/platform_submit.rs | 8 +- crates/platform/src/icebreakers/api.rs | 24 ++- crates/platform/src/icebreakers/manager.rs | 5 - crates/platform/src/load_balancer.rs | 24 +-- crates/platform/src/main.rs | 6 +- crates/platform/src/server.rs | 27 +-- crates/platform/src/server/routes.rs | 167 ++++++++++++++++-- crates/platform/src/server/routes/hidden.rs | 149 ---------------- crates/platform/src/server/routes/regular.rs | 14 -- crates/platform/src/server/state.rs | 12 -- docs/src/content/en/faq.mdx | 8 +- docs/src/content/en/verification.md | 5 +- docs/src/content/ja/faq.mdx | 8 +- docs/src/content/ja/verification.md | 5 +- 21 files changed, 210 insertions(+), 291 deletions(-) delete mode 100644 crates/platform/src/server/routes/hidden.rs delete mode 100644 crates/platform/src/server/routes/regular.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f02981df..714e48e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Removed - Gateway no longer performs a public port reachability check during registration. Relays connect outbound to the load balancers over WebSocket, so they no longer need a publicly routable inbound port. +- The platform no longer serves its API under a random UUID path prefix; all routes are now available directly at `/`. ## [1.0.0] - 2026-05-15 diff --git a/crates/integration_tests/src/gateway/mod.rs b/crates/integration_tests/src/gateway/mod.rs index 8d651655..3479ce06 100644 --- a/crates/integration_tests/src/gateway/mod.rs +++ b/crates/integration_tests/src/gateway/mod.rs @@ -10,9 +10,7 @@ use blockfrost_gateway::{ rate_limit::{self, RegisterRateLimiter}, types::AssetName, }; -use blockfrost_platform::{ - hydra_client, icebreakers::manager::IcebreakersManager, server::state::ApiPrefix, -}; +use blockfrost_platform::{hydra_client, icebreakers::manager::IcebreakersManager}; use reqwest::{Client, Response}; use serde::Deserialize; use serde_json::json; @@ -238,25 +236,24 @@ pub async fn wait_for_ready(client: &Client, url: &str, timeout: Duration) -> Re /// Common setup: start a `TestGateway` + Platform, wire through `IcebreakersManager`. /// /// Returns `(gateway, client, base_url_with_prefix)` for making requests. -pub async fn setup() -> (TestGateway, Client, String, ApiPrefix) { +pub async fn setup() -> (TestGateway, Client, String, uuid::Uuid) { crate::initialize_logging(); let gw = TestGateway::start().await; let gateway_url = format!("http://{}", gw.addr); - let (app, _, _, icebreakers_api, api_prefix) = - crate::platform::build_app_non_solitary(Some(gateway_url)) - .await - .expect("Failed to build the application"); + let (app, _, _, icebreakers_api) = crate::platform::build_app_non_solitary(Some(gateway_url)) + .await + .expect("Failed to build the application"); let icebreakers_api = icebreakers_api.expect("icebreakers_api should be Some"); + let api_prefix = icebreakers_api.api_prefix(); let health_errors = Arc::new(Mutex::new(vec![])); let manager = IcebreakersManager::new( icebreakers_api, health_errors, app, - api_prefix.clone(), bf_common::DEFAULT_MAX_BODY_BYTES, ); @@ -270,7 +267,7 @@ pub async fn setup() -> (TestGateway, Client, String, ApiPrefix) { manager.run((kex_req_rx, kex_resp_tx, terminate_tx)).await; let client = Client::new(); - let base = format!("http://{}{}", gw.addr, api_prefix); + let base = format!("http://{}/{}", gw.addr, api_prefix); // Wait for the relay to be ready and for the Platform root to return 200. wait_for_ready(&client, &format!("{base}/"), Duration::from_secs(30)).await; diff --git a/crates/integration_tests/src/platform/mod.rs b/crates/integration_tests/src/platform/mod.rs index 0061e789..e25558cb 100644 --- a/crates/integration_tests/src/platform/mod.rs +++ b/crates/integration_tests/src/platform/mod.rs @@ -8,9 +8,7 @@ use bf_node::pool::NodePool; use blockfrost_platform::config::{Config, DataNodeConfig, IcebreakersConfig, Mode}; use blockfrost_platform::genesis::genesis; use blockfrost_platform::{ - AppError, health_monitor, - icebreakers::api::IcebreakersAPI, - server::{build, state::ApiPrefix}, + AppError, health_monitor, icebreakers::api::IcebreakersAPI, server::build, }; use std::{env, sync::Arc, time::Duration}; @@ -47,7 +45,6 @@ pub async fn build_app() -> Result< NodePool, health_monitor::HealthMonitor, Option>, - ApiPrefix, ), AppError, > { @@ -64,7 +61,6 @@ pub async fn build_app_non_solitary( NodePool, health_monitor::HealthMonitor, Option>, - ApiPrefix, ), AppError, > { @@ -120,7 +116,6 @@ pub async fn build_app_with_data_node( NodePool, health_monitor::HealthMonitor, Option>, - ApiPrefix, ), AppError, > { diff --git a/crates/integration_tests/tests/e2e_websocket.rs b/crates/integration_tests/tests/e2e_websocket.rs index 37074b0a..7d2fc224 100644 --- a/crates/integration_tests/tests/e2e_websocket.rs +++ b/crates/integration_tests/tests/e2e_websocket.rs @@ -116,8 +116,7 @@ async fn test_ws_invalid_credentials_rejected() { }; let config = test_config(Some(icebreakers_config)); - let (app, _, _, icebreakers_api, api_prefix) = - build(config).await.expect("Failed to build app"); + let (app, _, _, icebreakers_api) = build(config).await.expect("Failed to build app"); let icebreakers_api = icebreakers_api.expect("icebreakers_api should be Some"); let health_errors = Arc::new(Mutex::new(vec![])); @@ -126,7 +125,6 @@ async fn test_ws_invalid_credentials_rejected() { icebreakers_api, health_errors.clone(), app, - api_prefix, bf_common::DEFAULT_MAX_BODY_BYTES, ); diff --git a/crates/integration_tests/tests/platform_data_node.rs b/crates/integration_tests/tests/platform_data_node.rs index 34cd6958..051ec560 100644 --- a/crates/integration_tests/tests/platform_data_node.rs +++ b/crates/integration_tests/tests/platform_data_node.rs @@ -34,7 +34,7 @@ async fn test_data_node_health_monitoring() { initialize_logging(); let mock = MockDataNode::healthy().await; - let (app, _, _, _, _) = build_app_with_data_node(mock.url) + let (app, _, _, _) = build_app_with_data_node(mock.url) .await .expect("Failed to build the application"); @@ -59,7 +59,7 @@ async fn test_data_node_unhealthy_status() { initialize_logging(); let mock = MockDataNode::unhealthy().await; - let (app, _, _, _, _) = build_app_with_data_node(mock.url) + let (app, _, _, _) = build_app_with_data_node(mock.url) .await .expect("Failed to build the application"); @@ -81,7 +81,7 @@ async fn test_data_node_unreachable() { initialize_logging(); let mock = MockDataNode::unreachable(); - let (app, _, _, _, _) = build_app_with_data_node(mock.url) + let (app, _, _, _) = build_app_with_data_node(mock.url) .await .expect("Failed to build the application"); diff --git a/crates/integration_tests/tests/platform_metrics.rs b/crates/integration_tests/tests/platform_metrics.rs index 339a342f..b7068556 100644 --- a/crates/integration_tests/tests/platform_metrics.rs +++ b/crates/integration_tests/tests/platform_metrics.rs @@ -12,7 +12,7 @@ use tower::ServiceExt; async fn test_route_metrics() { initialize_logging(); - let (app, _, _, _, _) = build_app().await.expect("Failed to build the application"); + let (app, _, _, _) = build_app().await.expect("Failed to build the application"); // Test without trailing slash let response = app diff --git a/crates/integration_tests/tests/platform_root.rs b/crates/integration_tests/tests/platform_root.rs index d0fe198a..b33a6029 100644 --- a/crates/integration_tests/tests/platform_root.rs +++ b/crates/integration_tests/tests/platform_root.rs @@ -14,7 +14,7 @@ use tower::ServiceExt; async fn test_route_root() { initialize_logging(); - let (app, _, _, _, _) = build_app().await.expect("Failed to build the application"); + let (app, _, _, _) = build_app().await.expect("Failed to build the application"); let response = app .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap()) diff --git a/crates/integration_tests/tests/platform_submit.rs b/crates/integration_tests/tests/platform_submit.rs index 8401e95b..b53d20b4 100644 --- a/crates/integration_tests/tests/platform_submit.rs +++ b/crates/integration_tests/tests/platform_submit.rs @@ -15,7 +15,7 @@ use tower::ServiceExt; #[ntest::timeout(120_000)] async fn test_route_submit_cbor_error() { initialize_logging(); - let (app, _, _, _, _) = build_app().await.expect("Failed to build the application"); + let (app, _, _, _) = build_app().await.expect("Failed to build the application"); let tx = "AAAAAA"; @@ -48,7 +48,7 @@ async fn test_route_submit_cbor_error() { #[ntest::timeout(120_000)] async fn test_route_submit_error() { initialize_logging(); - let (app, _, _, _, _) = build_app().await.expect("Failed to build the application"); + let (app, _, _, _) = build_app().await.expect("Failed to build the application"); let tx = "84a300d90102818258205176274bef11d575edd6aa72392aaf993a07f736e70239c1fb22d4b1426b22bc01018282583900ddf1eb9ce2a1561e8f156991486b97873fb6969190cbc99ddcb3816621dcb03574152623414ed354d2d8f50e310f3f2e7d167cb20e5754271a003d09008258390099a5cb0fa8f19aba38cacf8a243d632149129f882df3a8e67f6bd512bcb0cde66a545e9fbc7ca4492f39bca1f4f265cc1503b4f7d6ff205c1b000000024f127a7c021a0002a2ada100d90102818258208b83e59abc9d7a66a77be5e0825525546a595174f8b929f164fcf5052d7aab7b5840709c64556c946abf267edd90b8027343d065193ef816529d8fa7aa2243f1fd2ec27036a677974199e2264cb582d01925134b9a20997d5a734da298df957eb002f5f6"; @@ -92,7 +92,7 @@ async fn test_route_submit_error() { #[ntest::timeout(120_000)] async fn test_route_submit_agent_dequeu() { initialize_logging(); - let (app, _, _, _, _) = build_app().await.expect("Failed to build the application"); + let (app, _, _, _) = build_app().await.expect("Failed to build the application"); let tx = "84a800848258204c16d304e6d531c59afd87a9199b7bb4175bc131b3d6746917901046b662963c00825820893c3f630c0b2db16d041c388aa0d58746ccbbc44133b2d7a3127a72c79722f1018258200998adb591c872a241776e39fe855e04b2d7c361008e94c582f59b6b6ccc452c028258208380ce7240ba59187f6450911f74a70cf3d2749228badb2e7cd10fb6499355f503018482581d61e15900a9a62a8fb01f936a25bf54af209c7ed1248c4e5abd05ec4e76821a0023ba63a1581ca0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235a145484f534b5900a300581d71cba5c6770fe7b30ebc1fa32f01938c150513211360ded23ac76e36b301821a006336d5a3581c239075b83c03c2333eacd0b0beac6b8314f11ce3dc0c047012b0cad4a144706f6f6c01581c3547b4325e495d529619335603ababde10025dceafa9ed34b1fb6611a158208b284793d3bd4967244a2ddd68410d56d06d36ac8d201429b937096a2e8234bc1b7ffffffffffade6b581ca0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235a145484f534b59195e99028201d818583ad8799fd8799f4040ffd8799f581ca0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c23545484f534b59ff1a006336d5195e99ff825839016d06090559d8ed2988aa5b2fff265d668cf552f4f62278c0128f816c0a48432e080280d0d9b15edb65563995f97ce236035afea568e660d1821a00118f32a1581c2f8b2d1f384485896f38406173fa11df2a4ce53b4b0886138b76597aa1476261746368657201825839016d06090559d8ed2988aa5b2fff265d668cf552f4f62278c0128f816c0a48432e080280d0d9b15edb65563995f97ce236035afea568e660d11a06d9f713021a000ab9e00b582027f17979d848d6472896266dd8bf39f7251ca23798713464bc407bf637286c230d81825820cf5de9189b958f8ad64c1f1837c2fa4711d073494598467a1c1a59589393eae20310825839016d06090559d8ed2988aa5b2fff265d668cf552f4f62278c0128f816c0a48432e080280d0d9b15edb65563995f97ce236035afea568e660d11a08666c75111a001016d01282825820bf93dc59c10c19c35210c2414779d7391ca19128cc7b13794ea85af5ff835f59008258201c37df764f8261edce8678b197767668a91d544b2b203fb5d0cf9acc10366e7600a200818258200eabfa083d7969681d2fc8e825a5f79e1c40f03aeac46ecd94bf5c5790db1bc058409a029ddd3cdde65598bb712c640ea63eeebfee526ce49bd0983b4d1fdca858481ddf931bf0354552cc0a7d3365e2f03fdb457c0466cea8b371b645f9b6d0c2010582840001d8799fd8799f011a006336d5195e991b7ffffffffffade6bd8799f1a000539e7ff01ffff821a000b46e41a0a7f3ca4840003d87d80821a002dccfe1a28868be8f5f6"; @@ -127,7 +127,7 @@ async fn test_route_submit_agent_dequeu() { #[ntest::timeout(120_000)] async fn test_route_submit_success() { initialize_logging(); - let (app, _, _, _, _) = build_app().await.expect("Failed to build the application"); + let (app, _, _, _) = build_app().await.expect("Failed to build the application"); let blockfrost_client = get_blockfrost_client(); let tx = build_tx(&blockfrost_client).await.unwrap(); diff --git a/crates/platform/src/icebreakers/api.rs b/crates/platform/src/icebreakers/api.rs index b371e960..f404e865 100644 --- a/crates/platform/src/icebreakers/api.rs +++ b/crates/platform/src/icebreakers/api.rs @@ -1,11 +1,12 @@ use crate::config::Config; -use crate::{load_balancer::LoadBalancerConfig, server::state::ApiPrefix}; +use crate::load_balancer::LoadBalancerConfig; use bf_common::errors::AppError; use reqwest::Client; use serde::{Deserialize, Serialize}; use serde_json::json; use std::sync::Arc; use tracing::{info, warn}; +use uuid::Uuid; #[derive(Debug)] pub struct IcebreakersAPI { @@ -15,7 +16,8 @@ pub struct IcebreakersAPI { mode: String, port: u16, reward_address: String, - api_prefix: ApiPrefix, + /// A random identifier sent during registration. The gateway uses it to identify this relay + api_prefix: Uuid, } #[derive(Deserialize)] @@ -43,10 +45,7 @@ pub struct SuccessResponse { impl IcebreakersAPI { /// Creates a new `IcebreakersAPI` instance or logs a warning if not configured - pub async fn new( - config: &Config, - api_prefix: ApiPrefix, - ) -> Result>, AppError> { + pub async fn new(config: &Config) -> Result>, AppError> { match &config.icebreakers_config { Some(icebreakers_config) => { let api_url = icebreakers_config @@ -75,7 +74,7 @@ impl IcebreakersAPI { mode: config.mode.to_string(), port: config.server_port, reward_address: icebreakers_config.reward_address.clone(), - api_prefix, + api_prefix: Uuid::new_v4(), }; let icebreakers_api = Arc::new(icebreakers_api); @@ -100,6 +99,10 @@ impl IcebreakersAPI { } } + pub fn api_prefix(&self) -> Uuid { + self.api_prefix + } + /// Registers with the Icebreakers API pub async fn register(&self) -> Result { let url = format!("{}/register", self.base_url); @@ -108,7 +111,7 @@ impl IcebreakersAPI { "mode": self.mode, "port": self.port, "reward_address": self.reward_address, - "api_prefix": self.api_prefix.0.unwrap_or_default(), + "api_prefix": self.api_prefix, }); let response = self @@ -124,7 +127,10 @@ impl IcebreakersAPI { AppError::Registration(format!("Failed to parse success response: {e}")) })?; - info!("successfully registered with Icebreakers API"); + info!( + "successfully registered with Icebreakers API (route: {})", + success_response.route + ); // In case we get a URI without a protocol (http: or https: or ws: or wss:): let fallback_proto = if self.base_url.starts_with("https:") { diff --git a/crates/platform/src/icebreakers/manager.rs b/crates/platform/src/icebreakers/manager.rs index de4c01f5..ab1bb9e4 100644 --- a/crates/platform/src/icebreakers/manager.rs +++ b/crates/platform/src/icebreakers/manager.rs @@ -1,5 +1,4 @@ use crate::icebreakers::api::IcebreakersAPI; -use crate::server::state::ApiPrefix; use crate::{hydra_client, load_balancer}; use axum::Router; use bf_common::errors::BlockfrostError; @@ -10,7 +9,6 @@ pub struct IcebreakersManager { icebreakers_api: Arc, health_errors: Arc>>, app: Router, - api_prefix: ApiPrefix, max_response_body_bytes: usize, } @@ -19,14 +17,12 @@ impl IcebreakersManager { icebreakers_api: Arc, health_errors: Arc>>, app: Router, - api_prefix: ApiPrefix, max_response_body_bytes: usize, ) -> Self { Self { icebreakers_api, health_errors, app, - api_prefix, max_response_body_bytes, } } @@ -57,7 +53,6 @@ impl IcebreakersManager { tokio::spawn(load_balancer::run_all( self.app, self.health_errors, - self.api_prefix, Some(mutable_hydra_kex), self.icebreakers_api, self.max_response_body_bytes, diff --git a/crates/platform/src/load_balancer.rs b/crates/platform/src/load_balancer.rs index 5edb1137..44025db5 100644 --- a/crates/platform/src/load_balancer.rs +++ b/crates/platform/src/load_balancer.rs @@ -1,6 +1,5 @@ use crate::hydra_client; use crate::icebreakers::api::IcebreakersAPI; -use crate::server::state::ApiPrefix; use bf_common::errors::BlockfrostError; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; @@ -38,7 +37,6 @@ const PERIODIC_REREGISTER: std::time::Duration = std::time::Duration::from_secs( struct ConnContext { http_router: axum::Router, health_errors: Arc>>, - api_prefix: ApiPrefix, icebreakers_api: Arc, max_response_body_bytes: usize, } @@ -55,7 +53,6 @@ struct ConnContext { pub async fn run_all( http_router: axum::Router, health_errors: Arc>>, - api_prefix: ApiPrefix, hydra_kex: Option<( watch::Sender>>, mpsc::Sender, @@ -67,7 +64,6 @@ pub async fn run_all( let ctx = ConnContext { http_router, health_errors, - api_prefix, icebreakers_api, max_response_body_bytes, }; @@ -338,8 +334,6 @@ enum RelayMessage { } mod event_loop { - use crate::server::state::ApiPrefix; - use super::*; use tungstenite::protocol::Message; @@ -495,11 +489,9 @@ mod event_loop { LBEvent::NewLoadBalancerMessage(LoadBalancerMessage::Request(request)) => { let router = ctx.http_router.clone(); // cheap, and Axum also does it for each request let event_tx = event_tx.clone(); - let api_prefix = ctx.api_prefix.clone(); let max_response_body_bytes = ctx.max_response_body_bytes; tokio::spawn(async move { - let response = - handle_one(router, request, api_prefix, max_response_body_bytes).await; + let response = handle_one(router, request, max_response_body_bytes).await; let _ignored_failure: Result<_, _> = event_tx.send(LBEvent::NewResponse(response)).await; }); @@ -724,7 +716,6 @@ mod event_loop { async fn handle_one( http_router: axum::Router, request: JsonRequest, - api_prefix: ApiPrefix, max_response_body_bytes: usize, ) -> JsonResponse { use axum::body::Body; @@ -736,7 +727,7 @@ mod event_loop { let request_id_ = request.id.clone(); let rv: Result = async { - let req: Request = json_to_request(request, api_prefix)?; + let req: Request = json_to_request(request)?; let response: Response = tokio::time::timeout(REQUEST_TIMEOUT, http_router.into_service().oneshot(req)) @@ -771,7 +762,6 @@ mod event_loop { fn json_to_request( json: JsonRequest, - api_prefix: ApiPrefix, ) -> Result, (hyper::StatusCode, String)> { use axum::body::Body; use hyper::Request; @@ -796,8 +786,8 @@ fn json_to_request( }; let uri = match json.query { - Some(query) => format!("{}{}?{}", api_prefix, json.path, query), - None => format!("{}{}", api_prefix, json.path), + Some(query) => format!("{}?{}", json.path, query), + None => json.path, }; let mut rv = Request::builder().method(json.method.as_str()).uri(uri); @@ -859,7 +849,6 @@ async fn response_to_json( #[cfg(test)] mod tests { use super::*; - use crate::server::state::ApiPrefix; #[test] fn test_json_to_request_reconstructs_query() { @@ -872,12 +861,11 @@ mod tests { body_base64: String::new(), }; - let prefix = Uuid::nil(); - let request = json_to_request(request, ApiPrefix(Some(prefix))).unwrap(); + let request = json_to_request(request).unwrap(); assert_eq!( request.uri().path_and_query().unwrap().as_str(), - "/00000000-0000-0000-0000-000000000000/accounts/rewards?count=3&page=2&order=asc" + "/accounts/rewards?count=3&page=2&order=asc" ); } } diff --git a/crates/platform/src/main.rs b/crates/platform/src/main.rs index e14b9995..a5e79c02 100644 --- a/crates/platform/src/main.rs +++ b/crates/platform/src/main.rs @@ -35,8 +35,7 @@ async fn main() -> Result<(), AppError> { env!("GIT_REVISION") ); - let (app, _, health_monitor, icebreakers_api, api_prefix) = - build(config.clone().into()).await?; + let (app, _, health_monitor, icebreakers_api) = build(config.clone().into()).await?; let address = std::net::SocketAddr::new(config.server_address, config.server_port); let listener = tokio::net::TcpListener::bind(address).await?; @@ -64,7 +63,7 @@ async fn main() -> Result<(), AppError> { notify_server_ready.notified().await; - info!("Server is listening on http://{}{}", address, api_prefix); + info!("Server is listening on http://{}/", address); // Icebreakers registration and the load balancer task. // @@ -87,7 +86,6 @@ async fn main() -> Result<(), AppError> { icebreakers_api, health_errors, app, - api_prefix, config.max_response_body_bytes, ); diff --git a/crates/platform/src/server.rs b/crates/platform/src/server.rs index 990e8ff2..e095a92a 100644 --- a/crates/platform/src/server.rs +++ b/crates/platform/src/server.rs @@ -10,12 +10,11 @@ use bf_common::errors::{AppError, BlockfrostError}; use bf_data_node::client::DataNode; use bf_node::pool::NodePool; use metrics::{setup_metrics_recorder, spawn_process_collector}; -use routes::{hidden::get_hidden_api_routes, nest_routes, regular::get_regular_api_routes}; -use state::{ApiPrefix, AppState}; +use routes::get_api_routes; +use state::AppState; use std::sync::Arc; use tower::{Layer, limit::ConcurrencyLimitLayer}; use tower_http::normalize_path::NormalizePathLayer; -use uuid::Uuid; /// Builds and configures the Axum `Router`. /// Returns `Ok(Router)` on success or an `AppError` if a step fails. @@ -27,7 +26,6 @@ pub async fn build( NodePool, health_monitor::HealthMonitor, Option>, - ApiPrefix, ), AppError, > { @@ -64,18 +62,11 @@ pub async fn build( let health_monitor = health_monitor::HealthMonitor::spawn(node_conn_pool.clone(), data_node.clone()).await; - // Build a prefix - let api_prefix = ApiPrefix(config.icebreakers_config.as_ref().map(|_| Uuid::new_v4())); - // Set up optional Icebreakers API (solitary option in CLI) - let icebreakers_api = IcebreakersAPI::new(&config, api_prefix.clone()).await?; - - // API routes that are always under / (and also under the UUID prefix, if we use it) - let regular_api_routes = get_regular_api_routes(!config.no_metrics); - let hidden_api_routes = get_hidden_api_routes(!config.no_metrics); + let icebreakers_api = IcebreakersAPI::new(&config).await?; - // Nest under the UUID prefix - let api_routes = nest_routes(&api_prefix, regular_api_routes, hidden_api_routes); + // API routes + let api_routes = get_api_routes(!config.no_metrics); // Initialize the app state let app_state = AppState { @@ -104,11 +95,5 @@ pub async fn build( .fallback_service(inner) .layer(ConcurrencyLimitLayer::new(config.server_concurrency_limit)); - Ok(( - app, - node_conn_pool, - health_monitor, - icebreakers_api, - api_prefix, - )) + Ok((app, node_conn_pool, health_monitor, icebreakers_api)) } diff --git a/crates/platform/src/server/routes.rs b/crates/platform/src/server/routes.rs index 20e4a2d4..3fc87884 100644 --- a/crates/platform/src/server/routes.rs +++ b/crates/platform/src/server/routes.rs @@ -1,19 +1,152 @@ -pub mod hidden; -pub mod regular; - -use super::state::{ApiPrefix, AppState}; -use axum::Router; - -pub fn nest_routes( - prefix: &ApiPrefix, - regular: Router, - hidden: Router, -) -> Router { - if prefix.0.is_none() { - regular.merge(hidden) - } else { - regular - .clone() - .nest(&prefix.to_string(), regular.merge(hidden)) +use crate::api::{ + accounts, addresses, assets, blocks, epochs, governance, health, ledger, metadata, network, + pools, root, scripts, tx, txs, utils, +}; +use crate::middlewares::metrics::track_http_metrics; +use crate::server::state::AppState; +use axum::{ + Router, + middleware::from_fn, + routing::{get, post}, +}; + +pub fn get_api_routes(enable_metrics: bool) -> Router { + let mut router = Router::new() + .route("/", get(root::route)) + + // accounts + .route("/accounts/{stake_address}", get(accounts::stake_address::root::route)) + .route("/accounts/{stake_address}/rewards", get(accounts::stake_address::rewards::route)) + .route("/accounts/{stake_address}/history", get(accounts::stake_address::history::route)) + .route("/accounts/{stake_address}/delegations", get(accounts::stake_address::delegations::route)) + .route("/accounts/{stake_address}/registrations", get(accounts::stake_address::registrations::route)) + .route("/accounts/{stake_address}/withdrawals", get(accounts::stake_address::withdrawals::route)) + .route("/accounts/{stake_address}/mirs", get(accounts::stake_address::mirs::route)) + .route("/accounts/{stake_address}/addresses", get(accounts::stake_address::addresses::root::route)) + .route("/accounts/{stake_address}/addresses/assets", get(accounts::stake_address::addresses::assets::route)) + .route("/accounts/{stake_address}/addresses/total", get(accounts::stake_address::addresses::total::route)) + .route("/accounts/{stake_address}/utxos", get(accounts::stake_address::utxos::route)) + + // addresses + .route("/addresses/{address}", get(addresses::address::root::route)) + .route("/addresses/{address}/extended", get(addresses::address::extended::route)) + .route("/addresses/{address}/total", get(addresses::address::total::route)) + .route("/addresses/{address}/utxos", get(addresses::address::utxos::root::route)) + .route("/addresses/{address}/utxos/{asset}", get(addresses::address::utxos::asset::route)) + .route("/addresses/{address}/transactions", get(addresses::address::transactions::route)) + .route("/addresses/{address}/txs", get(addresses::address::txs::route)) + + // assets + .route("/assets", get(assets::root::route)) + .route("/assets/{asset}", get(assets::asset::root::route)) + .route("/assets/{asset}/history", get(assets::asset::history::route)) + .route("/assets/{asset}/transactions", get(assets::asset::transactions::route)) + .route("/assets/{asset}/addresses", get(assets::asset::addresses::route)) + .route("/assets/policy/{policy_id}", get(assets::policy::policy_id::route)) + + // blocks + .route("/blocks/epoch/{epoch_number}/slot/{slot_number}", get(blocks::epoch::epoch_number::slot::slot_number::route)) + .route("/blocks/slot/{slot_number}", get(blocks::slot::slot_number::route)) + .route("/blocks/latest", get(blocks::latest::root::route)) + .route("/blocks/latest/txs", get(blocks::latest::txs::route)) + .route("/blocks/{hash_or_number}", get(blocks::hash_or_number::root::route)) + .route("/blocks/{hash_or_number}/addresses", get(blocks::hash_or_number::addresses::route)) + .route("/blocks/{hash_or_number}/next", get(blocks::hash_or_number::next::route)) + .route("/blocks/{hash_or_number}/previous", get(blocks::hash_or_number::previous::route)) + .route("/blocks/{hash_or_number}/txs", get(blocks::hash_or_number::txs::route)) + + // epochs + .route("/epochs/latest", get(epochs::latest::root::route)) + .route("/epochs/latest/parameters", get(epochs::latest::parameters::route)) + .route("/epochs/{epoch_number}", get(epochs::number::root::route)) + .route("/epochs/{epoch_number}/next", get(epochs::number::next::route)) + .route("/epochs/{epoch_number}/previous", get(epochs::number::previous::route)) + .route("/epochs/{epoch_number}/stakes", get(epochs::number::stakes::root::route)) + .route("/epochs/{epoch_number}/stakes/{pool_id}", get(epochs::number::stakes::pool_id::route)) + .route("/epochs/{epoch_number}/blocks", get(epochs::number::blocks::root::route)) + .route("/epochs/{epoch_number}/blocks/{pool_id}", get(epochs::number::blocks::pool_id::route)) + .route("/epochs/{epoch_number}/parameters", get(epochs::number::parameters::route)) + + // health + .route("/health", get(health::root::route)) + .route("/health/clock", get(health::clock::route)) + + // ledger + .route("/genesis", get(ledger::genesis::route)) + + // governance + .route("/governance/dreps", get(governance::dreps::root::route)) + .route("/governance/dreps/{drep_id}", get(governance::dreps::drep_id::root::route)) + .route("/governance/dreps/{drep_id}/delegators", get(governance::dreps::drep_id::delegators::route)) + .route("/governance/dreps/{drep_id}/metadata", get(governance::dreps::drep_id::metadata::route)) + .route("/governance/dreps/{drep_id}/updates", get(governance::dreps::drep_id::updates::route)) + .route("/governance/dreps/{drep_id}/votes", get(governance::dreps::drep_id::votes::route)) + .route("/governance/proposals", get(governance::proposals::root::route)) + .route("/governance/proposals/{tx_hash}/{cert_index}", get(governance::proposals::tx_hash::cert_index::root::route)) + .route("/governance/proposals/{tx_hash}/{cert_index}/parameters", get(governance::proposals::tx_hash::cert_index::parameters::route)) + .route("/governance/proposals/{tx_hash}/{cert_index}/withdrawals", get(governance::proposals::tx_hash::cert_index::withdrawals::route)) + .route("/governance/proposals/{tx_hash}/{cert_index}/votes", get(governance::proposals::tx_hash::cert_index::votes::route)) + .route("/governance/proposals/{tx_hash}/{cert_index}/metadata", get(governance::proposals::tx_hash::cert_index::metadata::route)) + + // metadata + .route("/metadata/txs/labels", get(metadata::txs::labels::route)) + .route("/metadata/txs/labels/{label}", get(metadata::txs::label::root::route)) + .route("/metadata/txs/labels/{label}/cbor", get(metadata::txs::label::cbor::route)) + + // network + .route("/network", get(network::root::route)) + .route("/network/eras", get(network::eras::route)) + + // pools + .route("/pools", get(pools::root::route)) + .route("/pools/extended", get(pools::extended::route)) + .route("/pools/retired", get(pools::retired::route)) + .route("/pools/retiring", get(pools::retiring::route)) + .route("/pools/{pool_id}", get(pools::pool_id::root::route)) + .route("/pools/{pool_id}/history", get(pools::pool_id::history::route)) + .route("/pools/{pool_id}/metadata", get(pools::pool_id::metadata::route)) + .route("/pools/{pool_id}/relays", get(pools::pool_id::relays::route)) + .route("/pools/{pool_id}/delegators", get(pools::pool_id::delegators::route)) + .route("/pools/{pool_id}/blocks", get(pools::pool_id::blocks::route)) + .route("/pools/{pool_id}/updates", get(pools::pool_id::updates::route)) + .route("/pools/{pool_id}/votes", get(pools::pool_id::votes::route)) + + // tx + .route("/tx/submit", post(tx::submit::route)) + + // scripts + .route("/scripts", get(scripts::root::route)) + .route("/scripts/{script_hash}", get(scripts::script_hash::root::route)) + .route("/scripts/{script_hash}/json", get(scripts::script_hash::json::route)) + .route("/scripts/{script_hash}/cbor", get(scripts::script_hash::cbor::route)) + .route("/scripts/{script_hash}/redeemers", get(scripts::script_hash::redeemers::route)) + .route("/scripts/datum/{datum_hash}", get(scripts::datum::datum_hash::root::route)) + .route("/scripts/datum/{datum_hash}/cbor", get(scripts::datum::datum_hash::cbor::route)) + + // txs + .route("/txs/{hash}", get(txs::hash::root::route)) + .route("/txs/{hash}/utxos", get(txs::hash::utxos::route)) + .route("/txs/{hash}/stakes", get(txs::hash::stakes::route)) + .route("/txs/{hash}/delegations", get(txs::hash::delegations::route)) + .route("/txs/{hash}/withdrawals", get(txs::hash::withdrawals::route)) + .route("/txs/{hash}/mirs", get(txs::hash::mirs::route)) + .route("/txs/{hash}/pool_updates", get(txs::hash::pool_updates::route)) + .route("/txs/{hash}/pool_retires", get(txs::hash::pool_retires::route)) + .route("/txs/{hash}/metadata", get(txs::hash::metadata::root::route)) + .route("/txs/{hash}/metadata/cbor", get(txs::hash::metadata::cbor::route)) + .route("/txs/{hash}/redeemers", get(txs::hash::redeemers::route)) + .route("/txs/{hash}/required_signers", get(txs::hash::required_signers::route)) + .route("/txs/{hash}/cbor", get(txs::hash::cbor::route)) + + // utils + .route("/utils/tx/evaluate", post(utils::txs::evaluate::root::route)) + .route("/utils/tx/evaluate/utxos", post(utils::txs::evaluate::utxos::route)); + + if enable_metrics { + router = router + .route("/metrics", get(crate::api::metrics::route)) + .route_layer(from_fn(track_http_metrics)); } + + router } diff --git a/crates/platform/src/server/routes/hidden.rs b/crates/platform/src/server/routes/hidden.rs deleted file mode 100644 index f9b263f6..00000000 --- a/crates/platform/src/server/routes/hidden.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::api::{ - accounts, addresses, assets, blocks, epochs, governance, health, ledger, metadata, network, - pools, scripts, tx, txs, utils, -}; -use crate::middlewares::metrics::track_http_metrics; -use crate::server::state::AppState; -use axum::{ - Router, - middleware::from_fn, - routing::{get, post}, -}; - -/// API routes that are *only* under the UUID prefix -pub fn get_hidden_api_routes(enable_metrics: bool) -> Router { - let mut router = Router::new() - // accounts - .route("/accounts/{stake_address}", get(accounts::stake_address::root::route)) - .route("/accounts/{stake_address}/rewards", get(accounts::stake_address::rewards::route)) - .route("/accounts/{stake_address}/history", get(accounts::stake_address::history::route)) - .route("/accounts/{stake_address}/delegations", get(accounts::stake_address::delegations::route)) - .route("/accounts/{stake_address}/registrations", get(accounts::stake_address::registrations::route)) - .route("/accounts/{stake_address}/withdrawals", get(accounts::stake_address::withdrawals::route)) - .route("/accounts/{stake_address}/mirs", get(accounts::stake_address::mirs::route)) - .route("/accounts/{stake_address}/addresses", get(accounts::stake_address::addresses::root::route)) - .route("/accounts/{stake_address}/addresses/assets", get(accounts::stake_address::addresses::assets::route)) - .route("/accounts/{stake_address}/addresses/total", get(accounts::stake_address::addresses::total::route)) - .route("/accounts/{stake_address}/utxos", get(accounts::stake_address::utxos::route)) - - // addresses - .route("/addresses/{address}", get(addresses::address::root::route)) - .route("/addresses/{address}/extended", get(addresses::address::extended::route)) - .route("/addresses/{address}/total", get(addresses::address::total::route)) - .route("/addresses/{address}/utxos", get(addresses::address::utxos::root::route)) - .route("/addresses/{address}/utxos/{asset}", get(addresses::address::utxos::asset::route)) - .route("/addresses/{address}/transactions", get(addresses::address::transactions::route)) - .route("/addresses/{address}/txs", get(addresses::address::txs::route)) - - // assets - .route("/assets", get(assets::root::route)) - .route("/assets/{asset}", get(assets::asset::root::route)) - .route("/assets/{asset}/history", get(assets::asset::history::route)) - .route("/assets/{asset}/transactions", get(assets::asset::transactions::route)) - .route("/assets/{asset}/addresses", get(assets::asset::addresses::route)) - .route("/assets/policy/{policy_id}", get(assets::policy::policy_id::route)) - - // blocks - .route("/blocks/epoch/{epoch_number}/slot/{slot_number}", get(blocks::epoch::epoch_number::slot::slot_number::route)) - .route("/blocks/slot/{slot_number}", get(blocks::slot::slot_number::route)) - .route("/blocks/latest", get(blocks::latest::root::route)) - .route("/blocks/latest/txs", get(blocks::latest::txs::route)) - .route("/blocks/{hash_or_number}", get(blocks::hash_or_number::root::route)) - .route("/blocks/{hash_or_number}/addresses", get(blocks::hash_or_number::addresses::route)) - .route("/blocks/{hash_or_number}/next", get(blocks::hash_or_number::next::route)) - .route("/blocks/{hash_or_number}/previous", get(blocks::hash_or_number::previous::route)) - .route("/blocks/{hash_or_number}/txs", get(blocks::hash_or_number::txs::route)) - - // epochs - .route("/epochs/latest", get(epochs::latest::root::route)) - .route("/epochs/latest/parameters", get(epochs::latest::parameters::route)) - .route("/epochs/{epoch_number}", get(epochs::number::root::route)) - .route("/epochs/{epoch_number}/next", get(epochs::number::next::route)) - .route("/epochs/{epoch_number}/previous", get(epochs::number::previous::route)) - .route("/epochs/{epoch_number}/stakes", get(epochs::number::stakes::root::route)) - .route("/epochs/{epoch_number}/stakes/{pool_id}", get(epochs::number::stakes::pool_id::route)) - .route("/epochs/{epoch_number}/blocks", get(epochs::number::blocks::root::route)) - .route("/epochs/{epoch_number}/blocks/{pool_id}", get(epochs::number::blocks::pool_id::route)) - .route("/epochs/{epoch_number}/parameters", get(epochs::number::parameters::route)) - - // health - .route("/health", get(health::root::route)) - .route("/health/clock", get(health::clock::route)) - - // ledger - .route("/genesis", get(ledger::genesis::route)) - - // governance - .route("/governance/dreps", get(governance::dreps::root::route)) - .route("/governance/dreps/{drep_id}", get(governance::dreps::drep_id::root::route)) - .route("/governance/dreps/{drep_id}/delegators", get(governance::dreps::drep_id::delegators::route)) - .route("/governance/dreps/{drep_id}/metadata", get(governance::dreps::drep_id::metadata::route)) - .route("/governance/dreps/{drep_id}/updates", get(governance::dreps::drep_id::updates::route)) - .route("/governance/dreps/{drep_id}/votes", get(governance::dreps::drep_id::votes::route)) - .route("/governance/proposals", get(governance::proposals::root::route)) - .route("/governance/proposals/{tx_hash}/{cert_index}", get(governance::proposals::tx_hash::cert_index::root::route)) - .route("/governance/proposals/{tx_hash}/{cert_index}/parameters", get(governance::proposals::tx_hash::cert_index::parameters::route)) - .route("/governance/proposals/{tx_hash}/{cert_index}/withdrawals", get(governance::proposals::tx_hash::cert_index::withdrawals::route)) - .route("/governance/proposals/{tx_hash}/{cert_index}/votes", get(governance::proposals::tx_hash::cert_index::votes::route)) - .route("/governance/proposals/{tx_hash}/{cert_index}/metadata", get(governance::proposals::tx_hash::cert_index::metadata::route)) - - // metadata - .route("/metadata/txs/labels", get(metadata::txs::labels::route)) - .route("/metadata/txs/labels/{label}", get(metadata::txs::label::root::route)) - .route("/metadata/txs/labels/{label}/cbor", get(metadata::txs::label::cbor::route)) - - // network - .route("/network", get(network::root::route)) - .route("/network/eras", get(network::eras::route)) - - // pools - .route("/pools", get(pools::root::route)) - .route("/pools/extended", get(pools::extended::route)) - .route("/pools/retired", get(pools::retired::route)) - .route("/pools/retiring", get(pools::retiring::route)) - .route("/pools/{pool_id}", get(pools::pool_id::root::route)) - .route("/pools/{pool_id}/history", get(pools::pool_id::history::route)) - .route("/pools/{pool_id}/metadata", get(pools::pool_id::metadata::route)) - .route("/pools/{pool_id}/relays", get(pools::pool_id::relays::route)) - .route("/pools/{pool_id}/delegators", get(pools::pool_id::delegators::route)) - .route("/pools/{pool_id}/blocks", get(pools::pool_id::blocks::route)) - .route("/pools/{pool_id}/updates", get(pools::pool_id::updates::route)) - .route("/pools/{pool_id}/votes", get(pools::pool_id::votes::route)) - - // tx - .route("/tx/submit", post(tx::submit::route)) - - // scripts - .route("/scripts", get(scripts::root::route)) - .route("/scripts/{script_hash}", get(scripts::script_hash::root::route)) - .route("/scripts/{script_hash}/json", get(scripts::script_hash::json::route)) - .route("/scripts/{script_hash}/cbor", get(scripts::script_hash::cbor::route)) - .route("/scripts/{script_hash}/redeemers", get(scripts::script_hash::redeemers::route)) - .route("/scripts/datum/{datum_hash}", get(scripts::datum::datum_hash::root::route)) - .route("/scripts/datum/{datum_hash}/cbor", get(scripts::datum::datum_hash::cbor::route)) - - // txs - .route("/txs/{hash}", get(txs::hash::root::route)) - .route("/txs/{hash}/utxos", get(txs::hash::utxos::route)) - .route("/txs/{hash}/stakes", get(txs::hash::stakes::route)) - .route("/txs/{hash}/delegations", get(txs::hash::delegations::route)) - .route("/txs/{hash}/withdrawals", get(txs::hash::withdrawals::route)) - .route("/txs/{hash}/mirs", get(txs::hash::mirs::route)) - .route("/txs/{hash}/pool_updates", get(txs::hash::pool_updates::route)) - .route("/txs/{hash}/pool_retires", get(txs::hash::pool_retires::route)) - .route("/txs/{hash}/metadata", get(txs::hash::metadata::root::route)) - .route("/txs/{hash}/metadata/cbor", get(txs::hash::metadata::cbor::route)) - .route("/txs/{hash}/redeemers", get(txs::hash::redeemers::route)) - .route("/txs/{hash}/required_signers", get(txs::hash::required_signers::route)) - .route("/txs/{hash}/cbor", get(txs::hash::cbor::route)) - - // utils - .route("/utils/tx/evaluate", post(utils::txs::evaluate::root::route)) - .route("/utils/tx/evaluate/utxos", post(utils::txs::evaluate::utxos::route)); - - if enable_metrics { - router = router.route_layer(from_fn(track_http_metrics)); - } - - router -} diff --git a/crates/platform/src/server/routes/regular.rs b/crates/platform/src/server/routes/regular.rs deleted file mode 100644 index 57bfb62d..00000000 --- a/crates/platform/src/server/routes/regular.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::{api::root, middlewares::metrics::track_http_metrics, server::state::AppState}; -use axum::{Router, middleware::from_fn, routing::get}; - -pub fn get_regular_api_routes(enable_metrics: bool) -> Router { - let mut router = Router::new().route("/", get(root::route)); - - if enable_metrics { - router = router - .route("/metrics", get(crate::api::metrics::route)) - .route_layer(from_fn(track_http_metrics)); - } - - router -} diff --git a/crates/platform/src/server/state.rs b/crates/platform/src/server/state.rs index 1ec98a42..b4b3c9c4 100644 --- a/crates/platform/src/server/state.rs +++ b/crates/platform/src/server/state.rs @@ -19,15 +19,3 @@ impl AppState { } pub type AppStateExt = State; - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ApiPrefix(pub Option); - -impl std::fmt::Display for ApiPrefix { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.0 { - Some(u) => write!(f, "/{u}"), - None => write!(f, "/"), - } - } -} diff --git a/docs/src/content/en/faq.mdx b/docs/src/content/en/faq.mdx index defa66f9..50e34015 100644 --- a/docs/src/content/en/faq.mdx +++ b/docs/src/content/en/faq.mdx @@ -254,11 +254,9 @@ See the [configuration](/configuration) documentation for more details. ### I see warnings about old UUID paths after restarting my Icebreaker. Should I be concerned? -No, these warnings are typically not a concern. -Each restart generates a new random UUID path, and the Blockfrost servers may briefly attempt to contact the old path. -Unless the warnings persist, they can be safely ignored. -This is expected behavior and should not cause concern unless persistent issues occur. -If so, check your logs for errors. +No. +Current versions serve the API directly at `/`, without the random UUID path prefix, so these warnings no longer appear. +On older versions they were harmless: each restart generated a new random UUID path, and the Blockfrost servers could briefly attempt to contact the old one. ## Maintenance and advanced topics diff --git a/docs/src/content/en/verification.md b/docs/src/content/en/verification.md index 256568ab..1207be91 100644 --- a/docs/src/content/en/verification.md +++ b/docs/src/content/en/verification.md @@ -76,12 +76,13 @@ Once the service is running, verify that it is functioning correctly: When running in non-solitary mode, the Blockfrost platform generates a new UUID each time it starts. This UUID is used as a prefix for routing requests through the Icebreakers load balancers. +The platform's own HTTP API is served directly at `/`, without the prefix. ### Example log entry showing UUID ``` -INFO: Your instance ID: 3fa85f64-5717-4562-b3fc-2c963f66afa6 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +INFO: successfully registered with Icebreakers API (route: 3fa85f64-5717-4562-b3fc-2c963f66afa6) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` You would need this UUID for things like your own manual transaction submission tests. diff --git a/docs/src/content/ja/faq.mdx b/docs/src/content/ja/faq.mdx index 466ad9e2..9717ca4d 100644 --- a/docs/src/content/ja/faq.mdx +++ b/docs/src/content/ja/faq.mdx @@ -252,11 +252,9 @@ CLI に `--no-metrics` を渡したり、ウィザードで無効化を選択す ### Icebreaker を再起動した後に古い UUID パスに関する警告が出ます。心配すべきですか? -いいえ、通常これらの警告は心配する必要はありません。 -再起動のたびに新しいランダム UUID パスが生成されるため、Blockfrost サーバーが古いパスに対して短時間アクセスを試みることがあります。 -警告が継続しない限り、安全に無視できます。 -これは想定された動作であり、継続的に発生しない限り問題ありません。 -発生し続ける場合はログにエラーがないか確認してください。 +いいえ。 +現在のバージョンではランダムな UUID パスプレフィックスなしで API を `/` 直下で提供するため、これらの警告は表示されなくなりました。 +古いバージョンでは無害でした。再起動のたびに新しいランダム UUID パスが生成され、Blockfrost サーバーが古いパスに対して短時間アクセスを試みることがありました。 ## メンテナンスと高度なトピック diff --git a/docs/src/content/ja/verification.md b/docs/src/content/ja/verification.md index b01eb0de..222f87b4 100644 --- a/docs/src/content/ja/verification.md +++ b/docs/src/content/ja/verification.md @@ -76,12 +76,13 @@ blockfrost-platform --node-socket-path /path/to/node.socket \ 非ソリタリーモードで動作する場合、Blockfrost プラットフォームは起動のたびに新しい UUID を生成します。 この UUID は Icebreakers ロードバランサー経由のリクエストルーティングのプレフィックスとして使用されます。 +プラットフォーム自身の HTTP API は、プレフィックスなしで `/` 直下で提供されます。 ### UUID を含むログエントリの例 ``` -INFO: Your instance ID: 3fa85f64-5717-4562-b3fc-2c963f66afa6 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +INFO: successfully registered with Icebreakers API (route: 3fa85f64-5717-4562-b3fc-2c963f66afa6) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` 手動でのトランザクション送信テストなどではこの UUID が必要になります。