From 52e0e3a36f2558bc8ef5dcea4aee720b02c020a0 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Mon, 10 Oct 2022 21:13:01 -0700 Subject: [PATCH] Add /input page --- Cargo.lock | 1 + Cargo.toml | 1 + src/index.rs | 6 +- src/main.rs | 5 +- src/subcommand/server.rs | 79 ++++++++++++++----- .../server/deserialize_ordinal_from_str.rs | 7 +- src/subcommand/server/templates.rs | 22 ++++-- src/subcommand/server/templates/block.rs | 8 +- src/subcommand/server/templates/clock.rs | 54 ++++++------- src/subcommand/server/templates/home.rs | 2 +- src/subcommand/server/templates/input.rs | 74 +++++++++++++++++ src/subcommand/server/templates/ordinal.rs | 6 +- src/subcommand/server/templates/output.rs | 16 ++-- src/subcommand/server/templates/range.rs | 6 +- .../server/templates/transaction.rs | 14 ++-- src/test.rs | 5 +- static/index.css | 11 +++ templates/block.html | 4 +- templates/home.html | 2 +- templates/input.html | 16 ++++ templates/output.html | 6 +- templates/transaction.html | 8 +- tests/expected.rs | 2 +- tests/lib.rs | 1 + 24 files changed, 255 insertions(+), 101 deletions(-) create mode 100644 src/subcommand/server/templates/input.rs create mode 100644 templates/input.html diff --git a/Cargo.lock b/Cargo.lock index 4835796711..012651825c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1967,6 +1967,7 @@ dependencies = [ "env_logger", "executable-path", "futures 0.3.24", + "hex", "html-escaper", "http", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index d357261423..f8257d3da5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ derive_more = "0.99.17" dirs = "4.0.0" env_logger = "0.9.0" futures = "0.3.21" +hex = "0.4.3" html-escaper = "0.2.0" http = "0.2.6" lazy_static = "1.4.0" diff --git a/src/index.rs b/src/index.rs index f571ea9267..95322b4fde 100644 --- a/src/index.rs +++ b/src/index.rs @@ -251,7 +251,7 @@ impl Index { let mut errors = 0; let block = loop { - match self.block_at_height(height) { + match self.block(height) { Err(err) => { if cfg!(test) { return Err(err); @@ -488,7 +488,7 @@ impl Index { Ok(()) } - fn block_at_height(&self, height: u64) -> Result> { + pub(crate) fn block(&self, height: u64) -> Result> { Ok( self .client @@ -599,7 +599,7 @@ impl Index { pub(crate) fn blocktime(&self, height: Height) -> Result { let height = height.n(); - match self.block_at_height(height)? { + match self.block(height)? { Some(block) => Ok(Blocktime::Confirmed(block.header.time.into())), None => { let tx = self.database.begin_read()?; diff --git a/src/main.rs b/src/main.rs index a9cd311665..ab47539a2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,14 +22,15 @@ use { axum_server::Handle, bitcoin::{ blockdata::constants::COIN_VALUE, - consensus::{Decodable, Encodable}, + consensus::{self, Decodable, Encodable}, hash_types::BlockHash, hashes::Hash, - Address, Block, Network, OutPoint, Transaction, TxOut, Txid, + Address, Block, Network, OutPoint, Sequence, Transaction, TxIn, TxOut, Txid, }, chrono::{DateTime, NaiveDateTime, Utc}, clap::Parser, derive_more::{Display, FromStr}, + lazy_static::lazy_static, redb::{Database, ReadableTable, Table, TableDefinition, WriteTransaction}, regex::Regex, serde::{Deserialize, Serialize}, diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 5171794d2a..5f16ec1958 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -2,10 +2,10 @@ use super::*; use { self::{ - deserialize_ordinal_from_str::DeserializeOrdinalFromStr, + deserialize_ordinal_from_str::DeserializeFromStr, templates::{ - block::BlockHtml, clock::ClockSvg, home::HomeHtml, ordinal::OrdinalHtml, output::OutputHtml, - range::RangeHtml, rare::RareTxt, transaction::TransactionHtml, Content, PageHtml, + BlockHtml, ClockSvg, Content, HomeHtml, InputHtml, OrdinalHtml, OutputHtml, PageHtml, + RangeHtml, RareTxt, TransactionHtml, }, }, axum::{ @@ -13,7 +13,6 @@ use { http::header, response::{Redirect, Response}, }, - lazy_static::lazy_static, rust_embed::RustEmbed, rustls_acme::{ acme::{LETS_ENCRYPT_PRODUCTION_DIRECTORY, LETS_ENCRYPT_STAGING_DIRECTORY}, @@ -22,8 +21,7 @@ use { AcmeConfig, }, serde::{de, Deserializer}, - std::cmp::Ordering, - std::str, + std::{cmp::Ordering, str}, tokio_stream::StreamExt, }; @@ -141,6 +139,7 @@ impl Server { .route("/faq", get(Self::faq)) .route("/favicon.ico", get(Self::favicon)) .route("/height", get(Self::height)) + .route("/input/:block/:transaction/:input", get(Self::input)) .route("/ordinal/:ordinal", get(Self::ordinal)) .route("/output/:output", get(Self::output)) .route("/range/:start/:end", get(Self::range)) @@ -285,7 +284,7 @@ impl Server { async fn ordinal( index: extract::Extension>, - extract::Path(DeserializeOrdinalFromStr(ordinal)): extract::Path, + extract::Path(DeserializeFromStr(ordinal)): extract::Path>, ) -> impl IntoResponse { match index.blocktime(ordinal.height()) { Ok(blocktime) => OrdinalHtml { ordinal, blocktime }.page().into_response(), @@ -327,9 +326,10 @@ impl Server { } async fn range( - extract::Path((DeserializeOrdinalFromStr(start), DeserializeOrdinalFromStr(end))): extract::Path< - (DeserializeOrdinalFromStr, DeserializeOrdinalFromStr), - >, + extract::Path((DeserializeFromStr(start), DeserializeFromStr(end))): extract::Path<( + DeserializeFromStr, + DeserializeFromStr, + )>, ) -> impl IntoResponse { match start.cmp(&end) { Ordering::Equal => (StatusCode::BAD_REQUEST, Html("Empty Range".to_string())).into_response(), @@ -538,6 +538,29 @@ impl Server { } } + async fn input( + extract::Extension(index): extract::Extension>, + extract::Path(path): extract::Path<(u64, usize, usize)>, + ) -> Result { + let not_found = + || ServerError::NotFound(format!("Input /{}/{}/{} unknown", path.0, path.1, path.2)); + + let block = index + .block(path.0) + .map_err(ServerError::InternalError)? + .ok_or_else(not_found)?; + + let transaction = block.txdata.into_iter().nth(path.1).ok_or_else(not_found)?; + + let input = transaction + .input + .into_iter() + .nth(path.2) + .ok_or_else(not_found)?; + + Ok(InputHtml { path, input }.page()) + } + async fn faq() -> impl IntoResponse { Redirect::to("https://docs.ordinals.com/faq/") } @@ -1012,10 +1035,10 @@ mod tests { test_server.assert_response_regex( "/output/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0", StatusCode::OK, - ".*Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0.*

Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0

+ ".*Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0.*

Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0

value
5000000000
-
script pubkey
OP_PUSHBYTES_65 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG
+
script pubkey
OP_PUSHBYTES_65 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_CHECKSIG

1 Ordinal Range

    @@ -1060,7 +1083,7 @@ mod tests {
    block
    1

    Latest Blocks

    -
      +
      1. [[:xdigit:]]{64}
      2. 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
      .*", @@ -1076,7 +1099,7 @@ mod tests { test_server.assert_response_regex( "/", StatusCode::OK, - ".*
        \n(
      1. [[:xdigit:]]{64}
      2. \n){100}
      .*" + ".*
        \n(
      1. [[:xdigit:]]{64}
      2. \n){100}
      .*" ); } @@ -1147,13 +1170,13 @@ mod tests { test_server.assert_response_regex( &format!("/block/{block_hash}"), StatusCode::OK, - ".*

      Block [[:xdigit:]]{64}

      + ".*

      Block [[:xdigit:]]{64}

      height
      2
      timestamp
      0
      size
      203
      weight
      812
      -
      prev blockhash
      659f9b67fbc0b5cba0ef6ebc0aea322e1c246e29e43210bd581f5f3bd36d17bf
      +
      prev blockhash
      659f9b67fbc0b5cba0ef6ebc0aea322e1c246e29e43210bd581f5f3bd36d17bf

      2 Transactions

        @@ -1174,16 +1197,16 @@ mod tests { &format!("/tx/{txid}"), StatusCode::OK, &format!( - ".*Transaction {txid}.*

        Transaction {txid}

        + ".*Transaction {txid}.*

        Transaction {txid}

        1 Output

        .*" @@ -1215,4 +1238,22 @@ mod tests { ", ); } + + #[test] + fn input() { + TestServer::new().assert_response_regex( + "/input/0/0/0", + StatusCode::OK, + ".*Input /0/0/0.*

        Input /0/0/0

        .*
        text
        .*The Times 03/Jan/2009 Chancellor on brink of second bailout for banks
        .*", + ); + } + + #[test] + fn input_missing() { + TestServer::new().assert_response( + "/input/1/1/1", + StatusCode::NOT_FOUND, + "Input /1/1/1 unknown", + ); + } } diff --git a/src/subcommand/server/deserialize_ordinal_from_str.rs b/src/subcommand/server/deserialize_ordinal_from_str.rs index 081df09dd7..3f7e0ea98e 100644 --- a/src/subcommand/server/deserialize_ordinal_from_str.rs +++ b/src/subcommand/server/deserialize_ordinal_from_str.rs @@ -1,8 +1,11 @@ use super::*; -pub(crate) struct DeserializeOrdinalFromStr(pub(crate) Ordinal); +pub(crate) struct DeserializeFromStr(pub(crate) T); -impl<'de> Deserialize<'de> for DeserializeOrdinalFromStr { +impl<'de, T: FromStr> Deserialize<'de> for DeserializeFromStr +where + T::Err: Display, +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/src/subcommand/server/templates.rs b/src/subcommand/server/templates.rs index 2506067a6c..ad815966fb 100644 --- a/src/subcommand/server/templates.rs +++ b/src/subcommand/server/templates.rs @@ -4,14 +4,20 @@ use { html_escaper::{Escape, Trusted}, }; -pub(crate) mod block; -pub(crate) mod clock; -pub(crate) mod home; -pub(crate) mod ordinal; -pub(crate) mod output; -pub(crate) mod range; -pub(crate) mod rare; -pub(crate) mod transaction; +pub(crate) use { + block::BlockHtml, clock::ClockSvg, home::HomeHtml, input::InputHtml, ordinal::OrdinalHtml, + output::OutputHtml, range::RangeHtml, rare::RareTxt, transaction::TransactionHtml, +}; + +mod block; +mod clock; +mod home; +mod input; +mod ordinal; +mod output; +mod range; +mod rare; +mod transaction; #[derive(Boilerplate)] pub(crate) struct PageHtml { diff --git a/src/subcommand/server/templates/block.rs b/src/subcommand/server/templates/block.rs index 946c355931..a8812f99cc 100644 --- a/src/subcommand/server/templates/block.rs +++ b/src/subcommand/server/templates/block.rs @@ -25,23 +25,23 @@ impl Content for BlockHtml { #[cfg(test)] mod tests { - use {super::*, pretty_assertions::assert_eq, unindent::Unindent}; + use super::*; #[test] fn block_html() { - assert_eq!( + pretty_assert_eq!( BlockHtml::new(bitcoin::blockdata::constants::genesis_block( Network::Bitcoin ), Height(0)) .to_string(), " -

        Block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

        +

        Block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

        height
        0
        timestamp
        1231006505
        size
        285
        weight
        1140
        -
        prev blockhash
        0000000000000000000000000000000000000000000000000000000000000000
        +
        prev blockhash
        0000000000000000000000000000000000000000000000000000000000000000

        1 Transaction

          diff --git a/src/subcommand/server/templates/clock.rs b/src/subcommand/server/templates/clock.rs index 6ee561adf1..8757b2048b 100644 --- a/src/subcommand/server/templates/clock.rs +++ b/src/subcommand/server/templates/clock.rs @@ -25,51 +25,51 @@ impl ClockSvg { #[cfg(test)] mod tests { - use {super::*, pretty_assertions::assert_eq}; + use super::*; #[test] fn second() { - assert_eq!(ClockSvg::new(Height(0)).second, 0.0); - assert_eq!(ClockSvg::new(Height(504)).second, 90.0); - assert_eq!(ClockSvg::new(Height(1008)).second, 180.0); - assert_eq!(ClockSvg::new(Height(1512)).second, 270.0); - assert_eq!(ClockSvg::new(Height(2016)).second, 0.0); - assert_eq!(ClockSvg::new(Height(6930000)).second, 180.0); - assert_eq!(ClockSvg::new(Height(6930504)).second, 270.0); + pretty_assert_eq!(ClockSvg::new(Height(0)).second, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(504)).second, 90.0); + pretty_assert_eq!(ClockSvg::new(Height(1008)).second, 180.0); + pretty_assert_eq!(ClockSvg::new(Height(1512)).second, 270.0); + pretty_assert_eq!(ClockSvg::new(Height(2016)).second, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(6930000)).second, 180.0); + pretty_assert_eq!(ClockSvg::new(Height(6930504)).second, 270.0); } #[test] fn minute() { - assert_eq!(ClockSvg::new(Height(0)).minute, 0.0); - assert_eq!(ClockSvg::new(Height(52500)).minute, 90.0); - assert_eq!(ClockSvg::new(Height(105000)).minute, 180.0); - assert_eq!(ClockSvg::new(Height(157500)).minute, 270.0); - assert_eq!(ClockSvg::new(Height(210000)).minute, 0.0); - assert_eq!(ClockSvg::new(Height(6930000)).minute, 0.0); - assert_eq!(ClockSvg::new(Height(6930001)).minute, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(0)).minute, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(52500)).minute, 90.0); + pretty_assert_eq!(ClockSvg::new(Height(105000)).minute, 180.0); + pretty_assert_eq!(ClockSvg::new(Height(157500)).minute, 270.0); + pretty_assert_eq!(ClockSvg::new(Height(210000)).minute, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(6930000)).minute, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(6930001)).minute, 0.0); } #[test] fn hour() { - assert_eq!(ClockSvg::new(Height(0)).hour, 0.0); - assert_eq!(ClockSvg::new(Height(1732500)).hour, 90.0); - assert_eq!(ClockSvg::new(Height(3465000)).hour, 180.0); - assert_eq!(ClockSvg::new(Height(5197500)).hour, 270.0); - assert_eq!(ClockSvg::new(Height(6930000)).hour, 0.0); - assert_eq!(ClockSvg::new(Height(6930001)).hour, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(0)).hour, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(1732500)).hour, 90.0); + pretty_assert_eq!(ClockSvg::new(Height(3465000)).hour, 180.0); + pretty_assert_eq!(ClockSvg::new(Height(5197500)).hour, 270.0); + pretty_assert_eq!(ClockSvg::new(Height(6930000)).hour, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(6930001)).hour, 0.0); } #[test] fn final_subsidy_height() { - assert_eq!( + pretty_assert_eq!( ClockSvg::new(Height(6929999)).second, 1007.0 / 2016.0 * 360.0 ); - assert_eq!( + pretty_assert_eq!( ClockSvg::new(Height(6929999)).minute, 209_999.0 / 210_000.0 * 360.0 ); - assert_eq!( + pretty_assert_eq!( ClockSvg::new(Height(6929999)).hour, 6929999.0 / 6930000.0 * 360.0 ); @@ -77,9 +77,9 @@ mod tests { #[test] fn first_post_subsidy_height() { - assert_eq!(ClockSvg::new(Height(6930000)).second, 180.0); - assert_eq!(ClockSvg::new(Height(6930000)).minute, 0.0); - assert_eq!(ClockSvg::new(Height(6930000)).hour, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(6930000)).second, 180.0); + pretty_assert_eq!(ClockSvg::new(Height(6930000)).minute, 0.0); + pretty_assert_eq!(ClockSvg::new(Height(6930000)).hour, 0.0); } #[test] diff --git a/src/subcommand/server/templates/home.rs b/src/subcommand/server/templates/home.rs index c93feb9dfd..d4551242e6 100644 --- a/src/subcommand/server/templates/home.rs +++ b/src/subcommand/server/templates/home.rs @@ -59,7 +59,7 @@ mod tests {
          block
          1260001

          Latest Blocks

          -
            +
            1. 1{64}
            2. 0{64}
            diff --git a/src/subcommand/server/templates/input.rs b/src/subcommand/server/templates/input.rs new file mode 100644 index 0000000000..cedc37635a --- /dev/null +++ b/src/subcommand/server/templates/input.rs @@ -0,0 +1,74 @@ +use super::*; + +#[derive(Boilerplate)] +pub(crate) struct InputHtml { + pub(crate) path: (u64, usize, usize), + pub(crate) input: TxIn, +} + +impl Content for InputHtml { + fn title(&self) -> String { + format!("Input /{}/{}/{}", self.path.0, self.path.1, self.path.2) + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + bitcoin::{blockdata::script, Witness}, + }; + + #[test] + fn input_html() { + let mut witness = Witness::new(); + witness.push([1]); + pretty_assert_eq!( + InputHtml { + path: (1, 2, 3), + input: TxIn { + previous_output: "0000000000000000000000000000000000000000000000000000000000000000:0" + .parse() + .unwrap(), + script_sig: script::Builder::new().push_scriptint(4).into_script(), + sequence: Sequence(0), + witness, + } + } + .to_string(), + " +

            Input /1/2/3

            +
            +
            previous output
            0000000000000000000000000000000000000000000000000000000000000000:0
            +
            sequence
            0
            +
            witness
            010101
            +
            script sig
            OP_PUSHBYTES_1 04
            +
            text
            \x01\x04
            +
            + " + .unindent() + ); + } + + #[test] + fn skip_empty_items() { + pretty_assert_eq!( + InputHtml { + path: (1, 2, 3), + input: TxIn { + previous_output: OutPoint::null(), + script_sig: script::Builder::new().into_script(), + sequence: Sequence::MAX, + witness: Witness::new(), + } + } + .to_string(), + " +

            Input /1/2/3

            +
            +
            + " + .unindent() + ); + } +} diff --git a/src/subcommand/server/templates/ordinal.rs b/src/subcommand/server/templates/ordinal.rs index 6c6c7fe895..11b7421459 100644 --- a/src/subcommand/server/templates/ordinal.rs +++ b/src/subcommand/server/templates/ordinal.rs @@ -14,11 +14,11 @@ impl Content for OrdinalHtml { #[cfg(test)] mod tests { - use {super::*, pretty_assertions::assert_eq, unindent::Unindent}; + use super::*; #[test] fn ordinal_html() { - assert_eq!( + pretty_assert_eq!( OrdinalHtml { ordinal: Ordinal(0), blocktime: Blocktime::Confirmed(0), @@ -48,7 +48,7 @@ mod tests { #[test] fn ordinal_next_and_previous() { - assert_eq!( + pretty_assert_eq!( OrdinalHtml { ordinal: Ordinal(1), blocktime: Blocktime::Confirmed(0), diff --git a/src/subcommand/server/templates/output.rs b/src/subcommand/server/templates/output.rs index 2a4bb573bf..112033e24a 100644 --- a/src/subcommand/server/templates/output.rs +++ b/src/subcommand/server/templates/output.rs @@ -19,13 +19,11 @@ mod tests { use { super::*, bitcoin::{blockdata::script, PubkeyHash, Script}, - pretty_assertions::assert_eq, - unindent::Unindent, }; #[test] fn unspent_output() { - assert_eq!( + pretty_assert_eq!( OutputHtml { outpoint: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0" .parse() @@ -39,11 +37,11 @@ mod tests { } .to_string(), " -

            Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0

            +

            Output 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0

            value
            3
            -
            script pubkey
            OP_DUP OP_HASH160 OP_PUSHBYTES_20 0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG
            -
            address
            1111111111111111111114oLvT2
            +
            script pubkey
            OP_DUP OP_HASH160 OP_PUSHBYTES_20 0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG
            +
            address
            1111111111111111111114oLvT2

            2 Ordinal Ranges

              @@ -57,7 +55,7 @@ mod tests { #[test] fn spent_output() { - assert_eq!( + pretty_assert_eq!( OutputHtml { outpoint: "0000000000000000000000000000000000000000000000000000000000000000:0" .parse() @@ -71,10 +69,10 @@ mod tests { } .to_string(), " -

              Output 0000000000000000000000000000000000000000000000000000000000000000:0

              +

              Output 0000000000000000000000000000000000000000000000000000000000000000:0

              value
              1
              -
              script pubkey
              OP_0
              +
              script pubkey
              OP_0

              Output has been spent.

              " diff --git a/src/subcommand/server/templates/range.rs b/src/subcommand/server/templates/range.rs index 7cc3722b3c..757d975b6a 100644 --- a/src/subcommand/server/templates/range.rs +++ b/src/subcommand/server/templates/range.rs @@ -14,11 +14,11 @@ impl Content for RangeHtml { #[cfg(test)] mod tests { - use {super::*, pretty_assertions::assert_eq, unindent::Unindent}; + use super::*; #[test] fn range_html() { - assert_eq!( + pretty_assert_eq!( RangeHtml { start: Ordinal(0), end: Ordinal(1), @@ -37,7 +37,7 @@ mod tests { #[test] fn bugfix_broken_link() { - assert_eq!( + pretty_assert_eq!( RangeHtml { start: Ordinal(1), end: Ordinal(10), diff --git a/src/subcommand/server/templates/transaction.rs b/src/subcommand/server/templates/transaction.rs index 9412d8c752..dc2ffafcac 100644 --- a/src/subcommand/server/templates/transaction.rs +++ b/src/subcommand/server/templates/transaction.rs @@ -28,8 +28,6 @@ mod tests { use { super::*, bitcoin::{blockdata::script, PackedLockTime, TxOut}, - pretty_assertions::assert_eq, - unindent::Unindent, }; #[test] @@ -50,28 +48,28 @@ mod tests { ], }; - assert_eq!( + pretty_assert_eq!( TransactionHtml::new(transaction, Network::Bitcoin).to_string(), " -

              Transaction 9108ec7cbe9f1231dbf6374251b7267fb31cb23f36ed5a1d7344f5635b17dfe9

              +

              Transaction 9108ec7cbe9f1231dbf6374251b7267fb31cb23f36ed5a1d7344f5635b17dfe9

              2 Outputs

              diff --git a/src/test.rs b/src/test.rs index d3b7061cbc..db99cde61d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,4 +1,7 @@ -pub(crate) use {tempfile::TempDir, test_bitcoincore_rpc::TransactionTemplate}; +pub(crate) use { + pretty_assertions::assert_eq as pretty_assert_eq, tempfile::TempDir, + test_bitcoincore_rpc::TransactionTemplate, unindent::Unindent, +}; macro_rules! assert_regex_match { ($string:expr, $pattern:expr $(,)?) => { diff --git a/static/index.css b/static/index.css index 8e125e7a92..84d3122835 100644 --- a/static/index.css +++ b/static/index.css @@ -47,6 +47,11 @@ a:visited { color: var(--link); } +dt { + font-weight: bold; + margin-top: 0.5rem; +} + nav { display: flex; gap: 1rem; @@ -82,6 +87,7 @@ input[type=text] { } .blocks { + font-family: monospace, monospace; list-style-position: inside; padding-inline-start: 0; white-space: nowrap; @@ -91,6 +97,11 @@ input[type=text] { font-family: monospace, monospace; } +.data { + font-family: monospace, monospace; + overflow-wrap: break-word; +} + span.common, span.uncommon, span.rare, span.epic, span.legendary, span.mythic { border-radius: 0.25rem; padding: 0.125rem 0.25rem 0.125rem 0.25rem; diff --git a/templates/block.html b/templates/block.html index ca4df649fe..0b64b029b0 100644 --- a/templates/block.html +++ b/templates/block.html @@ -1,10 +1,10 @@ -

              Block {{ self.hash }}

              +

              Block {{ self.hash }}

              height
              {{self.height}}
              timestamp
              {{self.block.header.time}}
              size
              {{self.block.size()}}
              weight
              {{self.block.weight()}}
              -
              prev blockhash
              {{self.block.header.prev_blockhash}}
              +
              prev blockhash
              {{self.block.header.prev_blockhash}}

              {{"Transaction".tally(self.block.txdata.len())}}

                diff --git a/templates/home.html b/templates/home.html index ec6606d516..bb83e3cb4e 100644 --- a/templates/home.html +++ b/templates/home.html @@ -8,7 +8,7 @@

                Status

                %% }

                Latest Blocks

                -
                  +
                    %% for hash in &self.blocks {
                  1. {{hash}}
                  2. %% } diff --git a/templates/input.html b/templates/input.html new file mode 100644 index 0000000000..9b22120f97 --- /dev/null +++ b/templates/input.html @@ -0,0 +1,16 @@ +

                    Input /{{self.path.0}}/{{self.path.1}}/{{self.path.2}}

                    +
                    +%% if !self.input.previous_output.is_null() { +
                    previous output
                    {{self.input.previous_output}}
                    +%% } +%% if self.input.sequence != Sequence::MAX { +
                    sequence
                    {{self.input.sequence}}
                    +%% } +%% if !self.input.witness.is_empty() { +
                    witness
                    {{hex::encode(consensus::serialize(&self.input.witness))}}
                    +%% } +%% if !self.input.script_sig.is_empty() { +
                    script sig
                    {{self.input.script_sig.asm()}}
                    +
                    text
                    {{String::from_utf8_lossy(self.input.script_sig.as_bytes())}}
                    +%% } +
                    diff --git a/templates/output.html b/templates/output.html index cb6a6f39ef..b6aec5ffc9 100644 --- a/templates/output.html +++ b/templates/output.html @@ -1,9 +1,9 @@ -

                    Output {{self.outpoint}}

                    +

                    Output {{self.outpoint}}

                    value
                    {{ self.output.value }}
                    -
                    script pubkey
                    {{ self.output.script_pubkey.asm() }}
                    +
                    script pubkey
                    {{ self.output.script_pubkey.asm() }}
                    %% if let Ok(address) = Address::from_script(&self.output.script_pubkey, self.network) { -
                    address
                    {{ address }}
                    +
                    address
                    {{ address }}
                    %% }
                    %% match &self.list { diff --git a/templates/transaction.html b/templates/transaction.html index a1071ad9e7..897de4576b 100644 --- a/templates/transaction.html +++ b/templates/transaction.html @@ -1,17 +1,17 @@ -

                    Transaction {{self.txid}}

                    +

                    Transaction {{self.txid}}

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

                      %% for (vout, output) in self.transaction.output.iter().enumerate() { %% let outpoint = OutPoint::new(self.txid, vout as u32);
                    • - + {{ outpoint }}
                      value
                      {{ output.value }}
                      -
                      script pubkey
                      {{ output.script_pubkey.asm() }}
                      +
                      script pubkey
                      {{ output.script_pubkey.asm() }}
                      %% if let Ok(address) = Address::from_script(&output.script_pubkey, self.network) { -
                      address
                      {{ address }}
                      +
                      address
                      {{ address }}
                      %% }
                    • diff --git a/tests/expected.rs b/tests/expected.rs index 9659a71754..9df517d111 100644 --- a/tests/expected.rs +++ b/tests/expected.rs @@ -13,7 +13,7 @@ impl Expected { pub(crate) fn assert_match(&self, output: &str) { match self { - Self::String(string) => pretty_assertions::assert_eq!(output, string), + Self::String(string) => pretty_assert_eq!(output, string), Self::Regex(regex) => assert!( regex.is_match(output), "regex:\n{}\ndid not match output:\n{}", diff --git a/tests/lib.rs b/tests/lib.rs index 2c1b766753..68f0f987dc 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -4,6 +4,7 @@ use { self::{command_builder::CommandBuilder, expected::Expected}, executable_path::executable_path, nix::{sys::signal::Signal, unistd::Pid}, + pretty_assertions::assert_eq as pretty_assert_eq, regex::Regex, std::{ fs,