diff --git a/Cargo.lock b/Cargo.lock index 01a1df889e..e5f101c4bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -511,9 +511,9 @@ dependencies = [ [[package]] name = "boilerplate" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaf58d1a680b723bb9d9479db2fa886320a4af24f43570c3713fb26184ccdae" +checksum = "b5c87af1dbf3f6e0e54a084f14a161de67b0eb4eb36ce4cb40de60bf6afdf25b" dependencies = [ "darling", "mime", diff --git a/Cargo.toml b/Cargo.toml index a44558856f..0b0aaf34e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ axum = "0.6.1" axum-server = "0.4.0" base64 = "0.13.1" bitcoin = { version = "0.29.1", features = ["rand"] } -boilerplate = { version = "0.2.2", features = ["axum"] } +boilerplate = { version = "0.2.3", features = ["axum"] } chrono = "0.4.19" clap = { version = "3.1.0", features = ["derive"] } ctrlc = "3.2.1" diff --git a/src/inscription.rs b/src/inscription.rs index 809246b3aa..8b918d9051 100644 --- a/src/inscription.rs +++ b/src/inscription.rs @@ -83,6 +83,10 @@ impl Inscription { _ => None, } } + + pub(crate) fn content_html(&self) -> Trusted { + Trusted(ContentHtml(self.content())) + } } #[derive(Debug, PartialEq)] diff --git a/src/main.rs b/src/main.rs index ed5aaaaf29..4d26716a2f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use { ordinal::Ordinal, rarity::Rarity, sat_point::SatPoint, - subcommand::Subcommand, + subcommand::{server::templates::ContentHtml, Subcommand}, tally::Tally, }, anyhow::{anyhow, bail, Context, Error}, @@ -41,6 +41,7 @@ use { chrono::{NaiveDateTime, TimeZone, Utc}, clap::Parser, derive_more::{Display, FromStr}, + html_escaper::{Escape, Trusted}, regex::Regex, serde::{Deserialize, Serialize}, std::{ diff --git a/src/subcommand.rs b/src/subcommand.rs index 2cea1ec096..f5b6995374 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -6,7 +6,7 @@ mod index; mod info; mod list; mod parse; -mod server; +pub(crate) mod server; mod subsidy; mod supply; mod traits; diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 5f1b01f68b..b02d401270 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -31,7 +31,7 @@ use { }; mod deserialize_from_str; -mod templates; +pub(crate) mod templates; enum BlockQuery { Height(u64), @@ -475,6 +475,15 @@ impl Server { Extension(chain): Extension, Path(txid): Path, ) -> ServerResult { + let inscription = index + .get_inscription_by_inscription_id(txid) + .map_err(|err| { + ServerError::Internal(anyhow!( + "failed to retrieve inscription from txid {txid} from index: {err}" + )) + })? + .map(|(inscription, _satpoint)| inscription); + Ok( TransactionHtml::new( index @@ -485,6 +494,7 @@ impl Server { )) })? .ok_or_else(|| ServerError::NotFound(format!("transaction {txid} unknown")))?, + inscription, chain, ) .page( diff --git a/src/subcommand/server/templates.rs b/src/subcommand/server/templates.rs index fd77239e9e..a6ff77690f 100644 --- a/src/subcommand/server/templates.rs +++ b/src/subcommand/server/templates.rs @@ -1,17 +1,14 @@ -use { - super::*, - boilerplate::Boilerplate, - html_escaper::{Escape, Trusted}, -}; +use {super::*, boilerplate::Boilerplate}; pub(crate) use { - block::BlockHtml, clock::ClockSvg, home::HomeHtml, input::InputHtml, + block::BlockHtml, clock::ClockSvg, content::ContentHtml, home::HomeHtml, input::InputHtml, inscription::InscriptionHtml, ordinal::OrdinalHtml, output::OutputHtml, range::RangeHtml, rare::RareTxt, transaction::TransactionHtml, }; mod block; mod clock; +mod content; mod home; mod input; mod inscription; diff --git a/src/subcommand/server/templates/content.rs b/src/subcommand/server/templates/content.rs new file mode 100644 index 0000000000..10fd0734a4 --- /dev/null +++ b/src/subcommand/server/templates/content.rs @@ -0,0 +1,17 @@ +use super::*; + +pub(crate) struct ContentHtml<'a>(pub(crate) Option>); + +impl<'a> Display for ContentHtml<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self.0 { + Some(Content::Text(text)) => text.escape(f, false), + Some(Content::Png(png)) => write!( + f, + "", + base64::encode(png) + ), + None => write!(f, "UNKNOWN"), + } + } +} diff --git a/src/subcommand/server/templates/inscription.rs b/src/subcommand/server/templates/inscription.rs index 2dc5b56a0e..de64a7a325 100644 --- a/src/subcommand/server/templates/inscription.rs +++ b/src/subcommand/server/templates/inscription.rs @@ -54,7 +54,7 @@ mod tests {
satpoint
1111111111111111111111111111111111111111111111111111111111111111:1:0
- + " .unindent() ); diff --git a/src/subcommand/server/templates/transaction.rs b/src/subcommand/server/templates/transaction.rs index 3be68c5b85..d2a49ab278 100644 --- a/src/subcommand/server/templates/transaction.rs +++ b/src/subcommand/server/templates/transaction.rs @@ -2,17 +2,23 @@ use super::*; #[derive(Boilerplate)] pub(crate) struct TransactionHtml { - txid: Txid, - transaction: Transaction, chain: Chain, + inscription: Option, + transaction: Transaction, + txid: Txid, } impl TransactionHtml { - pub(crate) fn new(transaction: Transaction, chain: Chain) -> Self { + pub(crate) fn new( + transaction: Transaction, + inscription: Option, + chain: Chain, + ) -> Self { Self { txid: transaction.txid(), - transaction, chain, + inscription, + transaction, } } } @@ -49,7 +55,7 @@ mod tests { }; pretty_assert_eq!( - TransactionHtml::new(transaction, Chain::Mainnet).to_string(), + TransactionHtml::new(transaction, None, Chain::Mainnet).to_string(), "

Transaction 9108ec7cbe9f1231dbf6374251b7267fb31cb23f36ed5a1d7344f5635b17dfe9

2 Outputs

diff --git a/templates/inscription.html b/templates/inscription.html index 829d110097..9ea2ac4dc8 100644 --- a/templates/inscription.html +++ b/templates/inscription.html @@ -3,14 +3,4 @@

Inscription

satpoint
{{ self.satpoint }}
-%% match self.inscription.content() { -%% Some(Content::Text(text)) => { -{{ text }} -%% }, -%% Some(Content::Png(png)) => { - -%% }, -%% None => { -UNKNOWN -%% }, -%% } +{{ self.inscription.content_html() }} diff --git a/templates/ordinal.html b/templates/ordinal.html index 7e0925ca87..3490ab6894 100644 --- a/templates/ordinal.html +++ b/templates/ordinal.html @@ -13,17 +13,7 @@

Ordinal {{ self.ordinal.n() }}

time
{{ self.blocktime }}
%% if let Some(inscription) = &self.inscription {
inscription
-%% match inscription.content() { -%% Some(Content::Text(text)) => { -
{{ text }}
-%% }, -%% Some(Content::Png(png)) => { -
-%% }, -%% None => { -
UNKNOWN -%% } -%% } +
{{ inscription.content_html() }}
%% } %% if self.ordinal.n() > 0 { diff --git a/templates/transaction.html b/templates/transaction.html index 837244bc39..1586c9092c 100644 --- a/templates/transaction.html +++ b/templates/transaction.html @@ -1,4 +1,8 @@

Transaction {{self.txid}}

+%% if let Some(inscription) = &self.inscription { +

Inscription

+{{ inscription.content_html() }} +%% }

{{"Output".tally(self.transaction.output.len())}}

    %% for (vout, output) in self.transaction.output.iter().enumerate() { diff --git a/tests/lib.rs b/tests/lib.rs index 1a93c8aa4c..5b59ac82f8 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -33,6 +33,18 @@ macro_rules! assert_regex_match { }; } +fn reveal_txid_from_inscribe_stdout(stdout: &str) -> Txid { + stdout + .lines() + .nth(1) + .unwrap() + .split('\t') + .nth(1) + .unwrap() + .parse() + .unwrap() +} + mod command_builder; mod epochs; mod expected; diff --git a/tests/server.rs b/tests/server.rs index acb057edd0..ef48b1ba90 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -47,12 +47,11 @@ fn inscription_page() { .stdout_regex("commit\t[[:xdigit:]]{64}\nreveal\t[[:xdigit:]]{64}\n") .run(); - let reveal_tx = stdout.split("reveal\t").collect::>()[1].trim(); + let reveal_tx = reveal_txid_from_inscribe_stdout(&stdout); rpc_server.mine_blocks(1); - let ord_server = TestServer::spawn_with_args(&rpc_server, &[]); - ord_server.assert_response_regex( + TestServer::spawn_with_args(&rpc_server, &[]).assert_response_regex( &format!("/inscription/{}", reveal_tx), &format!( ".*

    Inscription

    @@ -63,19 +62,31 @@ fn inscription_page() { HELLOWORLD.*", ), ); +} - let ord_server = TestServer::spawn_with_args(&rpc_server, &[]); - ord_server.assert_response_regex( - &format!("/inscription/{}", reveal_tx), - &format!( - ".*

    Inscription

    -
    -
    satpoint
    -
    {reveal_tx}:0:0
    -
    +#[test] +fn inscription_appears_on_reveal_transaction_page() { + let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord"); + let txid = rpc_server.mine_blocks(1)[0].txdata[0].txid(); + + let stdout = CommandBuilder::new(format!( + "--chain regtest wallet inscribe --satpoint {txid}:0:0 --file hello.txt" + )) + .write("hello.txt", "HELLOWORLD") + .rpc_server(&rpc_server) + .stdout_regex("commit\t[[:xdigit:]]{64}\nreveal\t[[:xdigit:]]{64}\n") + .run(); + + let reveal_tx = reveal_txid_from_inscribe_stdout(&stdout); + + rpc_server.mine_blocks(1); + + TestServer::spawn_with_args(&rpc_server, &[]).assert_response_regex( + &format!("/tx/{}", reveal_tx), + ".*

    Transaction .*

    .* +

    Inscription

    HELLOWORLD.*", - ), - ) + ); } #[test] @@ -91,7 +102,7 @@ fn inscription_page_after_send() { .stdout_regex("commit\t[[:xdigit:]]{64}\nreveal\t[[:xdigit:]]{64}\n") .run(); - let reveal_txid = stdout.split("reveal\t").collect::>()[1].trim(); + let reveal_txid = reveal_txid_from_inscribe_stdout(&stdout); rpc_server.mine_blocks(1); diff --git a/tests/wallet.rs b/tests/wallet.rs index ac5584346d..775c79dd43 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -1,17 +1,5 @@ use {super::*, std::str::FromStr}; -fn reveal_txid_from_inscribe_stdout(stdout: &str) -> Txid { - stdout - .lines() - .nth(1) - .unwrap() - .split('\t') - .nth(1) - .unwrap() - .parse() - .unwrap() -} - #[test] fn satoshis() { let rpc_server = test_bitcoincore_rpc::spawn(); @@ -509,7 +497,7 @@ fn inscriptions_cannot_be_sent_by_satpoint() { .stdout_regex("commit\t[[:xdigit:]]{64}\nreveal\t[[:xdigit:]]{64}\n") .run(); - let reveal_txid = stdout.split("reveal\t").collect::>()[1].trim(); + let reveal_txid = reveal_txid_from_inscribe_stdout(&stdout); rpc_server.mine_blocks(1);