Skip to content

Commit

Permalink
Recursive endpoint for retrieving details about an inscription
Browse files Browse the repository at this point in the history
  • Loading branch information
lifofifoX committed Nov 4, 2023
1 parent 8e8449b commit 048bc33
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 8 deletions.
66 changes: 61 additions & 5 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ use {
page_config::PageConfig,
runes::Rune,
templates::{
BlockHtml, BlockJson, ChildrenHtml, ClockSvg, HomeHtml, InputHtml, InscriptionHtml,
InscriptionJson, InscriptionsBlockHtml, InscriptionsHtml, InscriptionsJson, OutputHtml,
OutputJson, PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, PreviewImageHtml,
PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml,
PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, RunesHtml, SatHtml, SatJson, TransactionHtml,
BlockHtml, BlockJson, ChildrenHtml, ClockSvg, HomeHtml, InputHtml, InscriptionDetailsJson,
InscriptionHtml, InscriptionJson, InscriptionsBlockHtml, InscriptionsHtml, InscriptionsJson,
OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml,
PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml,
PreviewUnknownHtml, PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, RunesHtml, SatHtml,
SatJson, TransactionHtml,
},
},
axum::{
Expand Down Expand Up @@ -226,6 +227,10 @@ impl Server {
)
.route("/r/blockheight", get(Self::block_height))
.route("/r/blocktime", get(Self::block_time))
.route(
"/r/inscription/:inscription_id",
get(Self::inscription_details),
)
.route("/r/metadata/:inscription_id", get(Self::metadata))
.route("/range/:start/:end", get(Self::range))
.route("/rare.txt", get(Self::rare_txt))
Expand Down Expand Up @@ -712,6 +717,57 @@ impl Server {
Ok(Json(hex::encode(metadata)))
}

async fn inscription_details(
Extension(page_config): Extension<Arc<PageConfig>>,
Extension(index): Extension<Arc<Index>>,
Path(inscription_id): Path<InscriptionId>,
) -> ServerResult<Response> {
let inscription = index
.get_inscription_by_id(inscription_id)?
.ok_or_not_found(|| format!("inscription {inscription_id}"))?;

let entry = index
.get_inscription_entry(inscription_id)?
.ok_or_not_found(|| format!("inscription {inscription_id}"))?;

let satpoint = index
.get_inscription_satpoint_by_id(inscription_id)?
.ok_or_not_found(|| format!("inscription {inscription_id}"))?;

let output = if satpoint.outpoint == unbound_outpoint() {
None
} else {
Some(
index
.get_transaction(satpoint.outpoint.txid)?
.ok_or_not_found(|| format!("inscription {inscription_id} current transaction"))?
.output
.into_iter()
.nth(satpoint.outpoint.vout.try_into().unwrap())
.ok_or_not_found(|| format!("inscription {inscription_id} current transaction output"))?,
)
};

let address = output
.as_ref()
.and_then(|o| page_config.chain.address_from_script(&o.script_pubkey).ok())
.map(|address| address.to_string());

Ok(
Json(InscriptionDetailsJson {
address,
inscription_number: entry.inscription_number,
content_type: inscription.content_type().map(|s| s.to_string()),
content_length: inscription.content_length(),
genesis_fee: entry.fee,
genesis_height: entry.height,
satpoint: satpoint,
timestamp: timestamp(entry.timestamp).timestamp(),
})
.into_response(),
)
}

async fn status(Extension(index): Extension<Arc<Index>>) -> (StatusCode, &'static str) {
if index.is_unrecoverably_reorged() {
(
Expand Down
2 changes: 1 addition & 1 deletion src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub(crate) use {
home::HomeHtml,
iframe::Iframe,
input::InputHtml,
inscription::{InscriptionHtml, InscriptionJson},
inscription::{InscriptionDetailsJson, InscriptionHtml, InscriptionJson},
inscriptions::{InscriptionsHtml, InscriptionsJson},
inscriptions_block::InscriptionsBlockHtml,
metadata::MetadataHtml,
Expand Down
12 changes: 12 additions & 0 deletions src/templates/inscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ pub(crate) struct InscriptionHtml {
pub(crate) timestamp: DateTime<Utc>,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct InscriptionDetailsJson {
pub address: Option<String>,
pub inscription_number: i64,
pub content_type: Option<String>,
pub content_length: Option<usize>,
pub genesis_fee: u64,
pub genesis_height: u64,
pub satpoint: SatPoint,
pub timestamp: i64,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct InscriptionJson {
pub address: Option<String>,
Expand Down
4 changes: 2 additions & 2 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use {
inscription_id::InscriptionId,
rarity::Rarity,
templates::{
block::BlockJson, inscription::InscriptionJson, inscriptions::InscriptionsJson,
output::OutputJson, sat::SatJson,
block::BlockJson, inscription::InscriptionDetailsJson, inscription::InscriptionJson,
inscriptions::InscriptionsJson, output::OutputJson, sat::SatJson,
},
SatPoint,
},
Expand Down
51 changes: 51 additions & 0 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,57 @@ fn inscription_metadata() {
);
}

#[test]
fn recursive_inscription_metadata() {
let rpc_server = test_bitcoincore_rpc::spawn();
create_wallet(&rpc_server);

rpc_server.mine_blocks(1);

let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --file wizards.txt")
.write("wizards.txt", "THEWIZARDSOFORD")
.rpc_server(&rpc_server)
.run_and_deserialize_output::<Inscribe>();

let inscription = output
.inscriptions
.get(0)
.unwrap();

rpc_server.mine_blocks(1);

let response = TestServer::spawn_with_args(&rpc_server, &[])
.request(format!("/r/inscription/{}", inscription.id));

assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response.headers().get("content-type").unwrap(),
"application/json"
);

let mut inscription_metadata_json: InscriptionDetailsJson =
serde_json::from_str(&response.text().unwrap()).unwrap();
assert_regex_match!(inscription_metadata_json.address.unwrap(), r"bc1p.*");
inscription_metadata_json.address = None;

pretty_assert_eq!(
inscription_metadata_json,
InscriptionDetailsJson {
address: None,
inscription_number: 0,
content_type: Some("text/plain;charset=utf-8".to_string()),
content_length: Some(15),
genesis_fee: 141,
genesis_height: 2,
satpoint: SatPoint {
outpoint: inscription.location.outpoint,
offset: 0,
},
timestamp: 2,
}
)
}

#[test]
fn inscriptions_page() {
let rpc_server = test_bitcoincore_rpc::spawn();
Expand Down

0 comments on commit 048bc33

Please sign in to comment.