diff --git a/src/index.rs b/src/index.rs index cc02c604e3..c46f83551a 100644 --- a/src/index.rs +++ b/src/index.rs @@ -228,6 +228,22 @@ impl Index { ) } + pub(crate) fn all(&self) -> Result> { + let mut blocks = Vec::new(); + + let tx = self.database.begin_read()?; + + let height_to_hash = tx.open_table(HEIGHT_TO_HASH)?; + + let mut cursor = height_to_hash.range(0..)?; + + while let Some(next) = cursor.next() { + blocks.push(sha256d::Hash::from_slice(next.1)?); + } + + Ok(blocks) + } + fn index_transaction( &self, txid: Txid, diff --git a/src/main.rs b/src/main.rs index 2b12b022a4..6a93ab5bea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,9 @@ use { options::Options, ordinal::Ordinal, sat_point::SatPoint, subcommand::Subcommand, }, anyhow::{anyhow, bail, Context, Error}, - axum::{extract, http::StatusCode, response::IntoResponse, routing::get, Json, Router}, + axum::{ + extract, http::StatusCode, response::Html, response::IntoResponse, routing::get, Json, Router, + }, axum_server::Handle, bdk::{ database::SqliteDatabase, @@ -17,9 +19,8 @@ use { }, bitcoin::{ blockdata::constants::COIN_VALUE, - consensus::Decodable, - consensus::Encodable, - hashes::{sha256, Hash, HashEngine}, + consensus::{Decodable, Encodable}, + hashes::{sha256, sha256d, Hash, HashEngine}, secp256k1::{ self, rand::{self, thread_rng}, diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 5fb95e0333..67becaad7a 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -60,6 +60,7 @@ impl Server { }); let app = Router::new() + .route("/", get(Self::root)) .route("/list/:outpoint", get(Self::list)) .route("/status", get(Self::status)) .layer(extract::Extension(index)) @@ -124,6 +125,34 @@ impl Server { }) } + async fn root(index: extract::Extension>) -> impl IntoResponse { + match index.all() { + Ok(blocks) => ( + StatusCode::OK, + Html(format!( + "", + blocks + .iter() + .enumerate() + .map(|(height, hash)| format!("
  • {height} - {hash}
  • \n")) + .collect::(), + )), + ), + Err(error) => { + eprintln!("Error serving request for root: {error}"); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Html( + StatusCode::INTERNAL_SERVER_ERROR + .canonical_reason() + .unwrap_or_default() + .to_string(), + ), + ) + } + } + } + async fn list( extract::Path(outpoint): extract::Path, index: extract::Extension>, diff --git a/tests/lib.rs b/tests/lib.rs index cb444aa05b..d02c50668d 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -306,7 +306,7 @@ impl Test { .get(&format!("http://127.0.0.1:{port}/{request}")) .send()?; assert_eq!(response.status().as_u16(), *status); - assert_eq!(response.text()?, *expected_response); + assert_eq!(response.text()?, *expected_response.unindent().trim_end()); successful_requests += 1; } } diff --git a/tests/server.rs b/tests/server.rs index c76dcf114f..7096582a7b 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -49,6 +49,28 @@ fn continuously_index_ranges() -> Result { .run_server(port) } +#[test] +fn root() -> Result { + let port = free_port()?; + + Test::new()? + .command(&format!("server --address 127.0.0.1 --http-port {port}")) + .request("/", 200, "
      \n
    ") + .block() + .block() + .request( + "/", + 200, + " +
      +
    • 0 - 14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b
    • +
    • 1 - 467a86f0642b1d284376d13a98ef58310caa49502b0f9a560ee222e0a122fe16
    • +
    + ", + ) + .run_server(port) +} + #[test] fn http_or_https_port_is_required() -> Result { Test::new()?