Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add very simple inscription page #817

Merged
merged 3 commits into from
Nov 21, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 29 additions & 5 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ mod updater;

const HEIGHT_TO_BLOCK_HASH: TableDefinition<u64, [u8; 32]> =
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
TableDefinition::new("HEIGHT_TO_BLOCK_HASH");
const ORDINAL_TO_INSCRIPTION: TableDefinition<u64, str> =
TableDefinition::new("ORDINAL_TO_INSCRIPTION");
const ORDINAL_TO_INSCRIPTION_TXID: TableDefinition<u64, [u8; 32]> =
TableDefinition::new("ORDINAL_TO_INSCRIPTION_TXID");
const TXID_TO_INSCRIPTION: TableDefinition<[u8; 32], str> =
TableDefinition::new("TXID_TO_INSCRIPTION");
const ORDINAL_TO_SATPOINT: TableDefinition<u64, [u8; 44]> =
TableDefinition::new("ORDINAL_TO_SATPOINT");
const OUTPOINT_TO_ORDINAL_RANGES: TableDefinition<[u8; 36], [u8]> =
Expand Down Expand Up @@ -149,7 +151,8 @@ impl Index {
};

tx.open_table(HEIGHT_TO_BLOCK_HASH)?;
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
tx.open_table(ORDINAL_TO_INSCRIPTION)?;
tx.open_table(ORDINAL_TO_INSCRIPTION_TXID)?;
tx.open_table(TXID_TO_INSCRIPTION)?;
tx.open_table(ORDINAL_TO_SATPOINT)?;
tx.open_table(OUTPOINT_TO_ORDINAL_RANGES)?;
tx.open_table(STATISTIC_TO_COUNT)?;
Expand Down Expand Up @@ -336,12 +339,33 @@ impl Index {
}

pub(crate) fn inscription(&self, ordinal: Ordinal) -> Result<Option<Inscription>> {
let db = self.database.begin_read()?;
let table = db.open_table(ORDINAL_TO_INSCRIPTION_TXID)?;

let Some(reveal_txid) = table.get(&ordinal.n())? else {
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
return Ok(None);
};

Ok(
self
.database
.begin_read()?
.open_table(TXID_TO_INSCRIPTION)?
.get(reveal_txid)?
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
.map(|inscription| {
serde_json::from_str(inscription)
.expect("failed to deserialize inscription (JSON) from database")
}),
)
}

pub(crate) fn inscription_from_txid(&self, txid: Txid) -> Result<Option<Inscription>> {
Ok(
self
.database
.begin_read()?
.open_table(ORDINAL_TO_INSCRIPTION)?
.get(&ordinal.n())?
.open_table(TXID_TO_INSCRIPTION)?
.get(txid.as_inner())?
.map(|inscription| {
serde_json::from_str(inscription)
.expect("failed to deserialize inscription (JSON) from database")
Expand Down
16 changes: 11 additions & 5 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ impl Updater {
) -> Result<()> {
let mut height_to_block_hash = wtx.open_table(HEIGHT_TO_BLOCK_HASH)?;
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
let mut ordinal_to_satpoint = wtx.open_table(ORDINAL_TO_SATPOINT)?;
let mut ordinal_to_inscription = wtx.open_table(ORDINAL_TO_INSCRIPTION)?;
let mut ordinal_to_inscription_txid = wtx.open_table(ORDINAL_TO_INSCRIPTION_TXID)?;
let mut txid_to_inscription = wtx.open_table(TXID_TO_INSCRIPTION)?;
let mut outpoint_to_ordinal_ranges = wtx.open_table(OUTPOINT_TO_ORDINAL_RANGES)?;

let start = Instant::now();
Expand Down Expand Up @@ -248,7 +249,8 @@ impl Updater {
txid,
tx,
&mut ordinal_to_satpoint,
&mut ordinal_to_inscription,
&mut ordinal_to_inscription_txid,
&mut txid_to_inscription,
&mut input_ordinal_ranges,
&mut ordinal_ranges_written,
&mut outputs_in_block,
Expand All @@ -262,7 +264,8 @@ impl Updater {
tx.txid(),
tx,
&mut ordinal_to_satpoint,
&mut ordinal_to_inscription,
&mut ordinal_to_inscription_txid,
&mut txid_to_inscription,
&mut coinbase_inputs,
&mut ordinal_ranges_written,
&mut outputs_in_block,
Expand All @@ -287,7 +290,8 @@ impl Updater {
txid: Txid,
tx: &Transaction,
ordinal_to_satpoint: &mut Table<u64, [u8; 44]>,
ordinal_to_inscription: &mut Table<u64, str>,
ordinal_to_inscription_txid: &mut Table<u64, [u8; 32]>,
txid_to_inscription: &mut Table<[u8; 32], str>,
input_ordinal_ranges: &mut VecDeque<(u64, u64)>,
ordinal_ranges_written: &mut u64,
outputs_traversed: &mut u64,
Expand All @@ -297,7 +301,9 @@ impl Updater {
{
let json = serde_json::to_string(&inscription)
.expect("Inscription serialization should always succeed");
ordinal_to_inscription.insert(&ordinal.n(), &json)?;

ordinal_to_inscription_txid.insert(&ordinal.n(), tx.txid().as_inner())?;
txid_to_inscription.insert(tx.txid().as_inner(), &json)?;
}
}

Expand Down
25 changes: 23 additions & 2 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use {
self::{
deserialize_from_str::DeserializeFromStr,
templates::{
BlockHtml, ClockSvg, Content, HomeHtml, InputHtml, OrdinalHtml, OutputHtml, PageHtml,
RangeHtml, RareTxt, TransactionHtml,
BlockHtml, ClockSvg, Content, HomeHtml, InputHtml, InscriptionHtml, OrdinalHtml, OutputHtml,
PageHtml, RangeHtml, RareTxt, TransactionHtml,
},
},
axum::{
Expand Down Expand Up @@ -157,6 +157,7 @@ impl Server {
.route("/favicon.ico", get(Self::favicon))
.route("/block-count", get(Self::block_count))
.route("/input/:block/:transaction/:input", get(Self::input))
.route("/inscription/:txid", get(Self::inscription))
.route("/ordinal/:ordinal", get(Self::ordinal))
.route("/output/:output", get(Self::output))
.route("/range/:start/:end", get(Self::range))
Expand Down Expand Up @@ -578,6 +579,26 @@ impl Server {
async fn bounties() -> Redirect {
Redirect::to("https://docs.ordinals.com/bounty/")
}

async fn inscription(
Extension(chain): Extension<Chain>,
Extension(index): Extension<Arc<Index>>,
Path(txid): Path<Txid>,
) -> ServerResult<PageHtml> {
Ok(
InscriptionHtml {
inscription: index
.inscription_from_txid(txid)
.map_err(|err| {
ServerError::Internal(anyhow!(
"failed to retrieve inscription from txid {txid} from index: {err}"
))
})?
.ok_or_else(|| ServerError::NotFound(format!("transaction {txid} has no inscription")))?,
}
.page(chain),
)
}
}

#[cfg(test)]
Expand Down
6 changes: 4 additions & 2 deletions src/subcommand/server/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ use {
};

pub(crate) use {
block::BlockHtml, clock::ClockSvg, home::HomeHtml, input::InputHtml, ordinal::OrdinalHtml,
output::OutputHtml, range::RangeHtml, rare::RareTxt, transaction::TransactionHtml,
block::BlockHtml, clock::ClockSvg, home::HomeHtml, input::InputHtml,
inscription::InscriptionHtml, ordinal::OrdinalHtml, output::OutputHtml, range::RangeHtml,
rare::RareTxt, transaction::TransactionHtml,
};

mod block;
mod clock;
mod home;
mod input;
mod inscription;
mod ordinal;
mod output;
mod range;
Expand Down
32 changes: 32 additions & 0 deletions src/subcommand/server/templates/inscription.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use super::*;

#[derive(Boilerplate)]
pub(crate) struct InscriptionHtml {
pub(crate) inscription: Inscription,
}

impl Content for InscriptionHtml {
fn title(&self) -> String {
"foo".into()
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn inscription_html() {
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
pretty_assert_eq!(
InscriptionHtml {
inscription: Inscription::Text("HELLOWORLD".into()),
}
.to_string(),
"
<h1>Inscription</h1>
<h3>HELLOWORLD</h3>
"
.unindent()
);
}
}
9 changes: 9 additions & 0 deletions templates/inscription.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h1>Inscription</h1>
%% match &self.inscription {
%% Inscription::Text(content) => {
<h3>{{ content }}</h3>
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
%% },
%% Inscription::Png(content) => {
<h3><img src="data:image/png;base64,{{ base64::encode(&content) }}"></h3>
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
%% },
%% }
25 changes: 25 additions & 0 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,28 @@ fn run() {

child.kill().unwrap();
}

#[test]
fn inscription_page() {
let rpc_server = test_bitcoincore_rpc::spawn_with(Network::Regtest, "ord");
rpc_server.mine_blocks(1);

let output =
CommandBuilder::new("--chain regtest wallet inscribe --ordinal 5000000000 --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 = output.stdout.split("reveal\t").collect::<Vec<&str>>()[1];

rpc_server.mine_blocks(1);

let ord_server = TestServer::spawn(&rpc_server);

ord_server.assert_response_regex(
&format!("/inscription/{}", reveal_tx),
".*<h1>Inscription</h1>
<h3>HELLOWORLD</h3>.*",
)
}