diff --git a/src/index.rs b/src/index.rs index d4e2e7f300..f032ea4c44 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1486,22 +1486,6 @@ impl Index { self.client.get_raw_transaction(&txid, None).into_option() } - pub(crate) fn get_transaction_blockhash(&self, txid: Txid) -> Result> { - Ok( - self - .client - .get_raw_transaction_info(&txid, None) - .into_option()? - .and_then(|info| { - if info.in_active_chain.unwrap_or_default() { - info.blockhash - } else { - None - } - }), - ) - } - pub(crate) fn find(&self, sat: Sat) -> Result> { let sat = sat.0; let rtx = self.begin_read()?; diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 30d7e8ac48..fc07835aa3 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -9,13 +9,13 @@ use { crate::{ server_config::ServerConfig, templates::{ - BlockHtml, BlockJson, BlocksHtml, ChildrenHtml, ChildrenJson, ClockSvg, CollectionsHtml, - HomeHtml, InputHtml, InscriptionHtml, InscriptionJson, InscriptionsBlockHtml, - InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson, PageContent, PageHtml, - PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, - PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, - RangeHtml, RareTxt, RuneHtml, RuneJson, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, - SatInscriptionsJson, SatJson, TransactionHtml, + BlockHtml, BlockJson, BlocksHtml, BlocksJson, ChildrenHtml, ChildrenJson, ClockSvg, + CollectionsHtml, HomeHtml, InputHtml, InscriptionHtml, InscriptionJson, + InscriptionsBlockHtml, InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson, + PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, + PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, + PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, RuneJson, RunesHtml, RunesJson, SatHtml, + SatInscriptionJson, SatInscriptionsJson, SatJson, TransactionHtml, TransactionJson, }, }, axum::{ @@ -698,7 +698,8 @@ impl Server { async fn blocks( Extension(server_config): Extension>, Extension(index): Extension>, - ) -> ServerResult> { + AcceptJson(accept_json): AcceptJson, + ) -> ServerResult { task::block_in_place(|| { let blocks = index.blocks(100)?; let mut featured_blocks = BTreeMap::new(); @@ -709,7 +710,13 @@ impl Server { featured_blocks.insert(*hash, inscriptions); } - Ok(BlocksHtml::new(blocks, featured_blocks).page(server_config)) + Ok(if accept_json { + Json(BlocksJson::new(blocks, featured_blocks)).into_response() + } else { + BlocksHtml::new(blocks, featured_blocks) + .page(server_config) + .into_response() + }) }) } @@ -774,7 +781,8 @@ impl Server { Extension(server_config): Extension>, Extension(index): Extension>, Path(txid): Path, - ) -> ServerResult> { + AcceptJson(accept_json): AcceptJson, + ) -> ServerResult { task::block_in_place(|| { let transaction = index .get_transaction(txid)? @@ -782,19 +790,26 @@ impl Server { let inscription_count = index.inscription_count(txid)?; - let blockhash = index.get_transaction_blockhash(txid)?; - - Ok( + Ok(if accept_json { + Json(TransactionJson { + chain: server_config.chain, + etching: index.get_etching(txid)?, + inscription_count, + transaction, + txid, + }) + .into_response() + } else { TransactionHtml { - blockhash, transaction, txid, inscription_count, chain: server_config.chain, etching: index.get_etching(txid)?, } - .page(server_config), - ) + .page(server_config) + .into_response() + }) }) } diff --git a/src/templates.rs b/src/templates.rs index 87fc226a78..f8dbf1e7ba 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -2,7 +2,7 @@ use {super::*, boilerplate::Boilerplate}; pub(crate) use { block::{BlockHtml, BlockJson}, - blocks::BlocksHtml, + blocks::{BlocksHtml, BlocksJson}, children::{ChildrenHtml, ChildrenJson}, clock::ClockSvg, collections::CollectionsHtml, @@ -25,11 +25,11 @@ pub(crate) use { sat::{SatHtml, SatInscriptionJson, SatInscriptionsJson, SatJson}, server_config::ServerConfig, status::StatusHtml, - transaction::TransactionHtml, + transaction::{TransactionHtml, TransactionJson}, }; pub mod block; -mod blocks; +pub mod blocks; mod children; mod clock; pub mod collections; @@ -48,7 +48,7 @@ pub mod rune; pub mod runes; pub mod sat; pub mod status; -mod transaction; +pub mod transaction; #[derive(Boilerplate)] pub(crate) struct PageHtml { diff --git a/src/templates/blocks.rs b/src/templates/blocks.rs index 570b506c72..6a63b9e2d8 100644 --- a/src/templates/blocks.rs +++ b/src/templates/blocks.rs @@ -1,10 +1,12 @@ use super::*; -#[derive(Boilerplate)] -pub(crate) struct BlocksHtml { - last: u32, - blocks: Vec, - featured_blocks: BTreeMap>, +pub type BlocksJson = BlocksHtml; + +#[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)] +pub struct BlocksHtml { + pub last: u32, + pub blocks: Vec, + pub featured_blocks: BTreeMap>, } impl BlocksHtml { diff --git a/src/templates/transaction.rs b/src/templates/transaction.rs index 6bd269742c..a2f741bec3 100644 --- a/src/templates/transaction.rs +++ b/src/templates/transaction.rs @@ -1,13 +1,14 @@ use super::*; -#[derive(Boilerplate)] -pub(crate) struct TransactionHtml { - pub(crate) blockhash: Option, - pub(crate) chain: Chain, - pub(crate) etching: Option, - pub(crate) inscription_count: u32, - pub(crate) transaction: Transaction, - pub(crate) txid: Txid, +pub type TransactionJson = TransactionHtml; + +#[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)] +pub struct TransactionHtml { + pub chain: Chain, + pub etching: Option, + pub inscription_count: u32, + pub transaction: Transaction, + pub txid: Txid, } impl PageContent for TransactionHtml { @@ -47,7 +48,6 @@ mod tests { pretty_assert_eq!( TransactionHtml { - blockhash: None, chain: Chain::Mainnet, etching: None, inscription_count: 0, @@ -89,44 +89,4 @@ mod tests { .unindent() ); } - - #[test] - fn with_blockhash() { - let transaction = Transaction { - version: 2, - lock_time: LockTime::ZERO, - input: Vec::new(), - output: vec![ - TxOut { - value: 50 * COIN_VALUE, - script_pubkey: script::Builder::new().push_int(0).into_script(), - }, - TxOut { - value: 50 * COIN_VALUE, - script_pubkey: script::Builder::new().push_int(1).into_script(), - }, - ], - }; - - assert_regex_match!( - TransactionHtml { - blockhash: Some(blockhash(0)), - chain: Chain::Mainnet, - etching: None, - inscription_count: 0, - txid: transaction.txid(), - transaction, - } - .to_string(), - " -

Transaction [[:xdigit:]]{64}

-
-
block
-
0{64}
-
- .* - " - .unindent() - ); - } } diff --git a/src/test.rs b/src/test.rs index d358b81bda..1abe8b19d9 100644 --- a/src/test.rs +++ b/src/test.rs @@ -35,16 +35,6 @@ macro_rules! assert_matches { } } -pub(crate) fn blockhash(n: u64) -> BlockHash { - let hex = format!("{n:x}"); - - if hex.is_empty() || hex.len() > 1 { - panic!(); - } - - hex.repeat(64).parse().unwrap() -} - pub(crate) fn txid(n: u64) -> Txid { let hex = format!("{n:x}"); diff --git a/templates/transaction.html b/templates/transaction.html index 0324f7aee8..d1e9cc29bf 100644 --- a/templates/transaction.html +++ b/templates/transaction.html @@ -8,10 +8,6 @@

Inscription Geneses

%% }
-%% if let Some(blockhash) = self.blockhash { -
block
-
{{ blockhash }}
-%% } %% if let Some(rune) = self.etching {
etching
{{ rune }}
diff --git a/tests/json_api.rs b/tests/json_api.rs index 7702646d38..353f949e2e 100644 --- a/tests/json_api.rs +++ b/tests/json_api.rs @@ -390,6 +390,64 @@ fn get_block() { ); } +#[test] +fn get_blocks() { + let rpc_server = test_bitcoincore_rpc::spawn(); + + let blocks: Vec = rpc_server + .mine_blocks(101) + .iter() + .rev() + .take(100) + .map(|block| block.block_hash()) + .collect(); + + let response = TestServer::spawn_with_server_args(&rpc_server, &[], &["--enable-json-api"]) + .json_request("/blocks"); + + assert_eq!(response.status(), StatusCode::OK); + + let blocks_json: BlocksJson = serde_json::from_str(&response.text().unwrap()).unwrap(); + + pretty_assert_eq!( + blocks_json, + BlocksJson { + last: 101, + blocks: blocks.clone(), + featured_blocks: blocks + .into_iter() + .take(5) + .map(|block_hash| (block_hash, Vec::new())) + .collect(), + } + ); +} + +#[test] +fn get_transaction() { + let rpc_server = test_bitcoincore_rpc::spawn(); + + let transaction = rpc_server.mine_blocks(1)[0].txdata[0].clone(); + + let txid = transaction.txid(); + + let response = TestServer::spawn_with_server_args(&rpc_server, &[], &["--enable-json-api"]) + .json_request(format!("/tx/{txid}")); + + assert_eq!(response.status(), StatusCode::OK); + + assert_eq!( + serde_json::from_str::(&response.text().unwrap()).unwrap(), + TransactionJson { + chain: Chain::Mainnet, + etching: None, + inscription_count: 0, + transaction, + txid, + } + ); +} + #[test] fn get_status() { let rpc_server = test_bitcoincore_rpc::builder() diff --git a/tests/lib.rs b/tests/lib.rs index 5037851cca..96e788456d 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -14,8 +14,9 @@ use { rarity::Rarity, subcommand::runes::RuneInfo, templates::{ - block::BlockJson, inscription::InscriptionJson, inscriptions::InscriptionsJson, - output::OutputJson, rune::RuneJson, runes::RunesJson, sat::SatJson, status::StatusHtml, + block::BlockJson, blocks::BlocksJson, inscription::InscriptionJson, + inscriptions::InscriptionsJson, output::OutputJson, rune::RuneJson, runes::RunesJson, + sat::SatJson, status::StatusHtml, transaction::TransactionJson, }, Edict, InscriptionId, Rune, RuneEntry, RuneId, Runestone, SatPoint, },