From 34c5ecd2a641cb11ced5aece616b194d2f53245f Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 11 Oct 2022 14:58:55 -0700 Subject: [PATCH 1/2] Show inscriptions on /ordinal --- src/index.rs | 28 +++++++++++++++++++++- src/subcommand/server.rs | 27 ++++++++++++++++++++- src/subcommand/server/templates/ordinal.rs | 5 ++++ templates/ordinal.html | 4 ++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/index.rs b/src/index.rs index 0cd2001a69..d5bbfd1747 100644 --- a/src/index.rs +++ b/src/index.rs @@ -4,7 +4,7 @@ use { bitcoin::BlockHeader, bitcoincore_rpc::{json::GetBlockHeaderResult, Auth, Client}, rayon::iter::{IntoParallelRefIterator, ParallelIterator}, - redb::WriteStrategy, + redb::{MultimapTableDefinition, ReadableMultimapTable, WriteStrategy}, std::sync::atomic::{AtomicBool, Ordering}, }; @@ -14,6 +14,8 @@ const HASH_TO_RUNE: TableDefinition<[u8; 32], str> = TableDefinition::new("HASH_ const HEIGHT_TO_HASH: TableDefinition = TableDefinition::new("HEIGHT_TO_HASH"); const ORDINAL_TO_SATPOINT: TableDefinition = TableDefinition::new("ORDINAL_TO_SATPOINT"); +const ORDINAL_TO_RUNE_HASHES: MultimapTableDefinition = + MultimapTableDefinition::new("ORDINAL_TO_RUNE_HASHES"); const OUTPOINT_TO_ORDINAL_RANGES: TableDefinition<[u8; 36], [u8]> = TableDefinition::new("OUTPOINT_TO_ORDINAL_RANGES"); const STATISTICS: TableDefinition = TableDefinition::new("STATISTICS"); @@ -125,6 +127,7 @@ impl Index { tx }; + tx.open_multimap_table(ORDINAL_TO_RUNE_HASHES)?; tx.open_table(HASH_TO_RUNE)?; tx.open_table(HEIGHT_TO_HASH)?; tx.open_table(ORDINAL_TO_SATPOINT)?; @@ -408,6 +411,21 @@ impl Index { Ok(blocks) } + pub(crate) fn inscriptions(&self, ordinal: Ordinal) -> Result> { + let rtx = self.database.begin_read()?; + + let table = rtx.open_multimap_table(ORDINAL_TO_RUNE_HASHES)?; + + let mut values = table.get(&ordinal.0)?; + + let mut inscriptions = Vec::new(); + while let Some(value) = values.next() { + inscriptions.push(sha256::Hash::from_inner(*value)); + } + + Ok(inscriptions) + } + pub(crate) fn rare_ordinal_satpoints(&self) -> Result> { let mut result = Vec::new(); @@ -548,12 +566,20 @@ impl Index { pub(crate) fn insert_rune(&self, rune: &Rune) -> Result<(bool, sha256::Hash)> { let json = serde_json::to_string(rune)?; let hash = sha256::Hash::hash(json.as_ref()); + let wtx = self.database.begin_write()?; + let created = wtx .open_table(HASH_TO_RUNE)? .insert(hash.as_inner(), &json)? .is_none(); + + wtx + .open_multimap_table(ORDINAL_TO_RUNE_HASHES)? + .insert(&rune.ordinal.n(), &hash.into_inner())?; + wtx.commit()?; + Ok((created, hash)) } diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index f6e1820526..c2f45ed41a 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -294,6 +294,11 @@ impl Server { blocktime: index.blocktime(ordinal.height()).map_err(|err| { ServerError::Internal(anyhow!("Failed to retrieve blocktime from index: {err}")) })?, + inscriptions: index.inscriptions(ordinal).map_err(|err| { + ServerError::Internal(anyhow!( + "Failed to retrieve runes for ordinal {ordinal}: {err}" + )) + })?, } .page(), ) @@ -679,7 +684,7 @@ mod tests { fn assert_response(&self, path: &str, status: StatusCode, expected_response: &str) { let response = self.get(path); assert_eq!(response.status(), status, "{}", response.text().unwrap()); - assert_eq!(response.text().unwrap(), expected_response); + pretty_assert_eq!(response.text().unwrap(), expected_response); } fn assert_response_regex(&self, path: &str, status: StatusCode, regex: &str) { @@ -1354,4 +1359,24 @@ mod tests { r#"This ord instance only accepts regtest runes for publication"#, ); } + + #[test] + fn rune_appears_on_inscribed_ordinal() { + let test_server = TestServer::new(); + + test_server.assert_put( + "/rune", + "application/json", + r#"{"name": "foo", "chain": "regtest", "ordinal": 0}"#, + StatusCode::CREATED, + "8ca6ee12cb891766de56e5698a73cd6546f27a88bd27c8b8d914bc4162f9e4b5", + ); + + test_server.assert_response_regex( + "/ordinal/0", + StatusCode::OK, + ".*
inscriptions
+
8ca6ee12cb891766de56e5698a73cd6546f27a88bd27c8b8d914bc4162f9e4b5
.*", + ); + } } diff --git a/src/subcommand/server/templates/ordinal.rs b/src/subcommand/server/templates/ordinal.rs index 11b7421459..5dc182179d 100644 --- a/src/subcommand/server/templates/ordinal.rs +++ b/src/subcommand/server/templates/ordinal.rs @@ -4,6 +4,7 @@ use super::*; pub(crate) struct OrdinalHtml { pub(crate) ordinal: Ordinal, pub(crate) blocktime: Blocktime, + pub(crate) inscriptions: Vec, } impl Content for OrdinalHtml { @@ -22,6 +23,7 @@ mod tests { OrdinalHtml { ordinal: Ordinal(0), blocktime: Blocktime::Confirmed(0), + inscriptions: Vec::new(), } .to_string(), " @@ -38,6 +40,7 @@ mod tests {
offset
0
rarity
mythic
time
1970-01-01 00:00:00
+
inscriptions
prev next @@ -52,6 +55,7 @@ mod tests { OrdinalHtml { ordinal: Ordinal(1), blocktime: Blocktime::Confirmed(0), + inscriptions: Vec::new(), } .to_string(), " @@ -68,6 +72,7 @@ mod tests {
offset
1
rarity
common
time
1970-01-01 00:00:00
+
inscriptions
prev next diff --git a/templates/ordinal.html b/templates/ordinal.html index e87144f597..f978333196 100644 --- a/templates/ordinal.html +++ b/templates/ordinal.html @@ -11,6 +11,10 @@

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

offset
{{ self.ordinal.third() }}
rarity
{{ self.ordinal.rarity() }}
time
{{ self.blocktime }}
+
inscriptions
+%% for hash in &self.inscriptions { +
{{hash}}
+%% } %% if self.ordinal.n() > 0 { prev From e87255d0a6dfe39e84008aaaaa70a050651996d3 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Tue, 11 Oct 2022 15:01:57 -0700 Subject: [PATCH 2/2] Show multiple runes --- src/subcommand/server.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index c2f45ed41a..c6ab6b0e54 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -1361,7 +1361,7 @@ mod tests { } #[test] - fn rune_appears_on_inscribed_ordinal() { + fn runes_appear_on_inscribed_ordinal() { let test_server = TestServer::new(); test_server.assert_put( @@ -1372,10 +1372,19 @@ mod tests { "8ca6ee12cb891766de56e5698a73cd6546f27a88bd27c8b8d914bc4162f9e4b5", ); + test_server.assert_put( + "/rune", + "application/json", + r#"{"name": "bar", "chain": "regtest", "ordinal": 0}"#, + StatusCode::CREATED, + "72ed622edc0e3753891809c931075f0da2c39ba491d2d715140208f930411339", + ); + test_server.assert_response_regex( "/ordinal/0", StatusCode::OK, ".*
inscriptions
+
72ed622edc0e3753891809c931075f0da2c39ba491d2d715140208f930411339
8ca6ee12cb891766de56e5698a73cd6546f27a88bd27c8b8d914bc4162f9e4b5
.*", ); }