From 88dcf0fb38c74f2b9101a92efd41daeaef656ea0 Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:11:06 +0700 Subject: [PATCH 01/12] merge upstream --- src/index.rs | 38 +++++++++++++++++++++++++++++++++++++- src/index/entry.rs | 2 +- src/subcommand/server.rs | 11 ++--------- src/templates.rs | 2 +- src/templates/rune.rs | 7 +++++++ 5 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/index.rs b/src/index.rs index 5f920eb085..744bcf5ac0 100644 --- a/src/index.rs +++ b/src/index.rs @@ -11,7 +11,7 @@ use { super::*, crate::{ subcommand::{find::FindRangeOutput, server::InscriptionQuery}, - templates::{RuneHtml, StatusHtml}, + templates::{RuneHtml, RuneJson, StatusHtml}, }, bitcoin::block::Header, bitcoincore_rpc::{json::GetBlockHeaderResult, Client}, @@ -913,6 +913,42 @@ impl Index { parent, })) } + pub(crate) fn rune_json(&self, rune: Rune) -> Result> { + let rtx = self.database.begin_read()?; + + let Some(id) = rtx + .open_table(RUNE_TO_RUNE_ID)? + .get(rune.0)? + .map(|guard| guard.value()) + else { + return Ok(None); + }; + + let entry = RuneEntry::load( + rtx + .open_table(RUNE_ID_TO_RUNE_ENTRY)? + .get(id)? + .unwrap() + .value(), + ); + + let parent = InscriptionId { + txid: entry.etching, + index: 0, + }; + + let parent = rtx + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? + .get(&parent.store())? + .is_some() + .then_some(parent); + + Ok(Some(RuneJson { + entry, + id: RuneId::load(id), + parent, + })) + } pub(crate) fn runes(&self) -> Result> { let mut entries = Vec::new(); diff --git a/src/index/entry.rs b/src/index/entry.rs index e5b1a9976c..8fe5e57516 100644 --- a/src/index/entry.rs +++ b/src/index/entry.rs @@ -28,7 +28,7 @@ impl Entry for Header { } } -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)] pub(crate) struct RuneEntry { pub(crate) burned: u128, pub(crate) deadline: Option, diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index d767ba53d6..8ab6e3d8b6 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -769,13 +769,8 @@ impl Server { async fn status( Extension(server_config): Extension>, Extension(index): Extension>, - AcceptJson(accept_json): AcceptJson, - ) -> ServerResult { - Ok(if accept_json { - Json(index.status()?).into_response() - } else { - index.status()?.page(server_config).into_response() - }) + ) -> ServerResult> { + Ok(index.status()?.page(server_config)) } async fn search_by_query( @@ -2557,8 +2552,6 @@ mod tests { StatusCode::OK, ".*

Status

-
chain
-
mainnet
height
0
inscriptions
diff --git a/src/templates.rs b/src/templates.rs index 4a53f94836..8f2ba7cc46 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -20,7 +20,7 @@ pub(crate) use { }, range::RangeHtml, rare::RareTxt, - rune::RuneHtml, + rune::{RuneHtml, RuneJson}, runes::RunesHtml, sat::{SatHtml, SatInscriptionJson, SatInscriptionsJson, SatJson}, server_config::ServerConfig, diff --git a/src/templates/rune.rs b/src/templates/rune.rs index 76ed61dbc0..e2bfb33145 100644 --- a/src/templates/rune.rs +++ b/src/templates/rune.rs @@ -7,6 +7,13 @@ pub(crate) struct RuneHtml { pub(crate) parent: Option, } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct RuneJson { + pub entry: RuneEntry, + pub id: RuneId, + pub parent: Option, +} + impl PageContent for RuneHtml { fn title(&self) -> String { format!("Rune {}", self.entry.spaced_rune()) From 58bf9c5fa1341312ea2bd74fe8d0b62083a03b9e Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Wed, 3 Jan 2024 14:08:06 +0700 Subject: [PATCH 02/12] implemented JSON formatting for Rune/Runes responses --- src/subcommand/server.rs | 16 ++++++++++++---- src/templates.rs | 2 +- src/templates/runes.rs | 5 +++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 8ab6e3d8b6..60fcc9e04f 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -44,6 +44,7 @@ use { set_header::SetResponseHeaderLayer, }, }; +use crate::templates::RunesJson; mod accept_encoding; mod accept_json; @@ -635,13 +636,20 @@ impl Server { async fn runes( Extension(server_config): Extension>, Extension(index): Extension>, - ) -> ServerResult> { - Ok( + AcceptJson(accept_json): AcceptJson + ) -> ServerResult { + Ok(if accept_json { + Json(RunesJson { + runes: index.runes()?, + }) + .into_response() + }else { RunesHtml { entries: index.runes()?, } - .page(server_config), - ) + .page(server_config) + .into_response() + }) } async fn home( diff --git a/src/templates.rs b/src/templates.rs index 8f2ba7cc46..b4df720f6e 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -21,7 +21,7 @@ pub(crate) use { range::RangeHtml, rare::RareTxt, rune::{RuneHtml, RuneJson}, - runes::RunesHtml, + runes::{RunesHtml, RunesJson}, sat::{SatHtml, SatInscriptionJson, SatInscriptionsJson, SatJson}, server_config::ServerConfig, status::StatusHtml, diff --git a/src/templates/runes.rs b/src/templates/runes.rs index 976714ab2f..0d10837c06 100644 --- a/src/templates/runes.rs +++ b/src/templates/runes.rs @@ -5,6 +5,11 @@ pub(crate) struct RunesHtml { pub(crate) entries: Vec<(RuneId, RuneEntry)>, } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct RunesJson { + pub runes: Vec<(RuneId, RuneEntry)> +} + impl PageContent for RunesHtml { fn title(&self) -> String { "Runes".to_string() From 1e6c5424ad35362cadf121ff4e475df780fd2ae9 Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:34:55 +0700 Subject: [PATCH 03/12] Fix format JSON runes response --- src/subcommand/server.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 60fcc9e04f..462f9dacf8 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -14,8 +14,8 @@ use { InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, - RangeHtml, RareTxt, RuneHtml, RunesHtml, SatHtml, SatInscriptionJson, SatInscriptionsJson, - SatJson, TransactionHtml, + RangeHtml, RareTxt, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, SatInscriptionsJson, + SatJson, StatusHtml, TransactionHtml, }, }, axum::{ @@ -44,7 +44,6 @@ use { set_header::SetResponseHeaderLayer, }, }; -use crate::templates::RunesJson; mod accept_encoding; mod accept_json; @@ -618,25 +617,31 @@ impl Server { Extension(server_config): Extension>, Extension(index): Extension>, Path(DeserializeFromStr(spaced_rune)): Path>, - ) -> ServerResult> { + AcceptJson(accept_json): AcceptJson, + ) -> ServerResult { if !index.has_rune_index() { return Err(ServerError::NotFound( "this server has no rune index".to_string(), )); } - Ok( + let output_rune_json = index.rune_json(spaced_rune.rune).unwrap(); + Ok(if accept_json { + Json(output_rune_json).into_response() + }else{ index - .rune_html(spaced_rune.rune)? - .ok_or_not_found(|| format!("rune {spaced_rune}"))? - .page(server_config), + .rune_html(spaced_rune.rune)? + .ok_or_not_found(|| format!("rune {spaced_rune}"))? + .page(server_config) + .into_response() + } ) } async fn runes( Extension(server_config): Extension>, Extension(index): Extension>, - AcceptJson(accept_json): AcceptJson + AcceptJson(accept_json): AcceptJson, ) -> ServerResult { Ok(if accept_json { Json(RunesJson { From 2c296435aed3001018992c7a4db6cd5130f82710 Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Thu, 4 Jan 2024 15:41:56 +0700 Subject: [PATCH 04/12] Add field in RuneJson format --- src/index.rs | 1 + src/templates/rune.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/index.rs b/src/index.rs index 744bcf5ac0..e4289fbd8b 100644 --- a/src/index.rs +++ b/src/index.rs @@ -945,6 +945,7 @@ impl Index { Ok(Some(RuneJson { entry, + rune: RuneId::load(id).into(), id: RuneId::load(id), parent, })) diff --git a/src/templates/rune.rs b/src/templates/rune.rs index e2bfb33145..cd6df68c95 100644 --- a/src/templates/rune.rs +++ b/src/templates/rune.rs @@ -11,6 +11,7 @@ pub(crate) struct RuneHtml { pub struct RuneJson { pub entry: RuneEntry, pub id: RuneId, + pub rune: u128, pub parent: Option, } From 543f459a8253c9cbb8a260fa9b1da45a77846bee Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Thu, 4 Jan 2024 22:10:18 +0700 Subject: [PATCH 05/12] Add run properties fields in RuneJson format --- src/index.rs | 4 +++- src/templates/rune.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/index.rs b/src/index.rs index e4289fbd8b..10e5bfda1a 100644 --- a/src/index.rs +++ b/src/index.rs @@ -943,9 +943,11 @@ impl Index { .is_some() .then_some(parent); + let rune_id = RuneId::load(id); Ok(Some(RuneJson { entry, - rune: RuneId::load(id).into(), + height: rune_id.height, + index: rune_id.index, id: RuneId::load(id), parent, })) diff --git a/src/templates/rune.rs b/src/templates/rune.rs index cd6df68c95..7eee8333be 100644 --- a/src/templates/rune.rs +++ b/src/templates/rune.rs @@ -11,7 +11,8 @@ pub(crate) struct RuneHtml { pub struct RuneJson { pub entry: RuneEntry, pub id: RuneId, - pub rune: u128, + pub height: u32, + pub index: u16, pub parent: Option, } From f7797d387f8e767044fe1a8ce132bc058412b036 Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Thu, 4 Jan 2024 23:19:19 +0700 Subject: [PATCH 06/12] Fix format --- src/index.rs | 16 ++++++++-------- src/subcommand/server.rs | 21 ++++++++++----------- src/templates/runes.rs | 2 +- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/index.rs b/src/index.rs index 10e5bfda1a..c563425423 100644 --- a/src/index.rs +++ b/src/index.rs @@ -926,10 +926,10 @@ impl Index { let entry = RuneEntry::load( rtx - .open_table(RUNE_ID_TO_RUNE_ENTRY)? - .get(id)? - .unwrap() - .value(), + .open_table(RUNE_ID_TO_RUNE_ENTRY)? + .get(id)? + .unwrap() + .value(), ); let parent = InscriptionId { @@ -938,10 +938,10 @@ impl Index { }; let parent = rtx - .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? - .get(&parent.store())? - .is_some() - .then_some(parent); + .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? + .get(&parent.store())? + .is_some() + .then_some(parent); let rune_id = RuneId::load(id); Ok(Some(RuneJson { diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 462f9dacf8..852605a7fc 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -628,14 +628,13 @@ impl Server { let output_rune_json = index.rune_json(spaced_rune.rune).unwrap(); Ok(if accept_json { Json(output_rune_json).into_response() - }else{ + } else { index - .rune_html(spaced_rune.rune)? - .ok_or_not_found(|| format!("rune {spaced_rune}"))? - .page(server_config) - .into_response() - } - ) + .rune_html(spaced_rune.rune)? + .ok_or_not_found(|| format!("rune {spaced_rune}"))? + .page(server_config) + .into_response() + }) } async fn runes( @@ -647,13 +646,13 @@ impl Server { Json(RunesJson { runes: index.runes()?, }) - .into_response() - }else { + .into_response() + } else { RunesHtml { entries: index.runes()?, } - .page(server_config) - .into_response() + .page(server_config) + .into_response() }) } diff --git a/src/templates/runes.rs b/src/templates/runes.rs index 0d10837c06..c7e4e8e91a 100644 --- a/src/templates/runes.rs +++ b/src/templates/runes.rs @@ -7,7 +7,7 @@ pub(crate) struct RunesHtml { #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct RunesJson { - pub runes: Vec<(RuneId, RuneEntry)> + pub runes: Vec<(RuneId, RuneEntry)>, } impl PageContent for RunesHtml { From 7f219bfc69f83717eb49c003976fb1112960144c Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Fri, 5 Jan 2024 00:54:54 +0700 Subject: [PATCH 07/12] Fix format JSON runes --- src/index.rs | 41 +--------------------------------------- src/subcommand/server.rs | 15 ++++++++++----- src/templates/rune.rs | 13 +++---------- src/templates/runes.rs | 8 +++----- 4 files changed, 17 insertions(+), 60 deletions(-) diff --git a/src/index.rs b/src/index.rs index c563425423..5f920eb085 100644 --- a/src/index.rs +++ b/src/index.rs @@ -11,7 +11,7 @@ use { super::*, crate::{ subcommand::{find::FindRangeOutput, server::InscriptionQuery}, - templates::{RuneHtml, RuneJson, StatusHtml}, + templates::{RuneHtml, StatusHtml}, }, bitcoin::block::Header, bitcoincore_rpc::{json::GetBlockHeaderResult, Client}, @@ -913,45 +913,6 @@ impl Index { parent, })) } - pub(crate) fn rune_json(&self, rune: Rune) -> Result> { - let rtx = self.database.begin_read()?; - - let Some(id) = rtx - .open_table(RUNE_TO_RUNE_ID)? - .get(rune.0)? - .map(|guard| guard.value()) - else { - return Ok(None); - }; - - let entry = RuneEntry::load( - rtx - .open_table(RUNE_ID_TO_RUNE_ENTRY)? - .get(id)? - .unwrap() - .value(), - ); - - let parent = InscriptionId { - txid: entry.etching, - index: 0, - }; - - let parent = rtx - .open_table(INSCRIPTION_ID_TO_SEQUENCE_NUMBER)? - .get(&parent.store())? - .is_some() - .then_some(parent); - - let rune_id = RuneId::load(id); - Ok(Some(RuneJson { - entry, - height: rune_id.height, - index: rune_id.index, - id: RuneId::load(id), - parent, - })) - } pub(crate) fn runes(&self) -> Result> { let mut entries = Vec::new(); diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 852605a7fc..b331007186 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -14,8 +14,8 @@ use { InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, - RangeHtml, RareTxt, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, SatInscriptionsJson, - SatJson, StatusHtml, TransactionHtml, + RangeHtml, RareTxt, RuneJson, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, + SatInscriptionsJson, SatJson, StatusHtml, TransactionHtml, }, }, axum::{ @@ -625,9 +625,14 @@ impl Server { )); } - let output_rune_json = index.rune_json(spaced_rune.rune).unwrap(); + let rune = index.rune_html(spaced_rune.rune)?.ok_or_not_found(|| format!("rune {spaced_rune}"))?; Ok(if accept_json { - Json(output_rune_json).into_response() + Json(RuneJson { + parent: rune.parent, + id: rune.id, + entry: rune.entry, + }) + .into_response() } else { index .rune_html(spaced_rune.rune)? @@ -644,7 +649,7 @@ impl Server { ) -> ServerResult { Ok(if accept_json { Json(RunesJson { - runes: index.runes()?, + entries: index.runes()?, }) .into_response() } else { diff --git a/src/templates/rune.rs b/src/templates/rune.rs index 7eee8333be..048d416fd7 100644 --- a/src/templates/rune.rs +++ b/src/templates/rune.rs @@ -1,21 +1,14 @@ use super::*; -#[derive(Boilerplate)] +pub(crate) type RuneJson = RuneHtml; + +#[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)] pub(crate) struct RuneHtml { pub(crate) entry: RuneEntry, pub(crate) id: RuneId, pub(crate) parent: Option, } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub struct RuneJson { - pub entry: RuneEntry, - pub id: RuneId, - pub height: u32, - pub index: u16, - pub parent: Option, -} - impl PageContent for RuneHtml { fn title(&self) -> String { format!("Rune {}", self.entry.spaced_rune()) diff --git a/src/templates/runes.rs b/src/templates/runes.rs index c7e4e8e91a..fc922f2ed9 100644 --- a/src/templates/runes.rs +++ b/src/templates/runes.rs @@ -1,14 +1,12 @@ use super::*; -#[derive(Boilerplate)] +pub(crate) type RunesJson = RunesHtml; + +#[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)] pub(crate) struct RunesHtml { pub(crate) entries: Vec<(RuneId, RuneEntry)>, } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub struct RunesJson { - pub runes: Vec<(RuneId, RuneEntry)>, -} impl PageContent for RunesHtml { fn title(&self) -> String { From 62052a1ccc55e896ec9c0601e90b7eb146c190e0 Mon Sep 17 00:00:00 2001 From: Lugon LQ <48004924+lugondev@users.noreply.github.com> Date: Fri, 5 Jan 2024 02:40:34 +0700 Subject: [PATCH 08/12] Fix format status page --- src/subcommand/server.rs | 17 +++++++++++++---- src/templates/runes.rs | 1 - 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index b331007186..1daab64be9 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -15,7 +15,7 @@ use { PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, RangeHtml, RareTxt, RuneJson, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, - SatInscriptionsJson, SatJson, StatusHtml, TransactionHtml, + SatInscriptionsJson, SatJson, TransactionHtml, }, }, axum::{ @@ -625,7 +625,9 @@ impl Server { )); } - let rune = index.rune_html(spaced_rune.rune)?.ok_or_not_found(|| format!("rune {spaced_rune}"))?; + let rune = index + .rune_html(spaced_rune.rune)? + .ok_or_not_found(|| format!("rune {spaced_rune}"))?; Ok(if accept_json { Json(RuneJson { parent: rune.parent, @@ -786,8 +788,13 @@ impl Server { async fn status( Extension(server_config): Extension>, Extension(index): Extension>, - ) -> ServerResult> { - Ok(index.status()?.page(server_config)) + AcceptJson(accept_json): AcceptJson, + ) -> ServerResult { + Ok(if accept_json { + Json(index.status()?).into_response() + } else { + index.status()?.page(server_config).into_response() + }) } async fn search_by_query( @@ -2569,6 +2576,8 @@ mod tests { StatusCode::OK, ".*

Status

+
chain
+
mainnet
height
0
inscriptions
diff --git a/src/templates/runes.rs b/src/templates/runes.rs index fc922f2ed9..d7334ad0b6 100644 --- a/src/templates/runes.rs +++ b/src/templates/runes.rs @@ -7,7 +7,6 @@ pub(crate) struct RunesHtml { pub(crate) entries: Vec<(RuneId, RuneEntry)>, } - impl PageContent for RunesHtml { fn title(&self) -> String { "Runes".to_string() From bf23db3d2c41287bb2a4453fcc612568e91a1b51 Mon Sep 17 00:00:00 2001 From: 0xLugon Date: Fri, 5 Jan 2024 02:54:40 +0700 Subject: [PATCH 09/12] Update src/subcommand/server.rs Refactor the code for better simplicity Co-authored-by: raph --- src/subcommand/server.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 1daab64be9..bf542736b7 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -625,15 +625,9 @@ impl Server { )); } - let rune = index - .rune_html(spaced_rune.rune)? - .ok_or_not_found(|| format!("rune {spaced_rune}"))?; Ok(if accept_json { - Json(RuneJson { - parent: rune.parent, - id: rune.id, - entry: rune.entry, - }) + Json(index + .rune_html(spaced_rune.rune)?).into_response() .into_response() } else { index From 3a7d3eabccad16c816716119e3fb965ebebc070c Mon Sep 17 00:00:00 2001 From: raphjaph Date: Thu, 4 Jan 2024 22:40:09 +0100 Subject: [PATCH 10/12] Add some tests --- src/index.rs | 37 ++------- src/index/entry.rs | 28 +++---- src/lib.rs | 4 +- src/subcommand/server.rs | 14 ++-- src/subcommand/wallet/etch.rs | 6 +- src/subcommand/wallet/send.rs | 2 +- src/templates.rs | 4 +- src/templates/rune.rs | 10 +-- src/templates/runes.rs | 6 +- tests/json_api.rs | 136 +++++++++++++++++++++++++++++++++- tests/lib.rs | 4 +- tests/test_server.rs | 7 +- 12 files changed, 187 insertions(+), 71 deletions(-) diff --git a/src/index.rs b/src/index.rs index 5f920eb085..9042ce20a3 100644 --- a/src/index.rs +++ b/src/index.rs @@ -11,7 +11,7 @@ use { super::*, crate::{ subcommand::{find::FindRangeOutput, server::InscriptionQuery}, - templates::{RuneHtml, StatusHtml}, + templates::StatusHtml, }, bitcoin::block::Header, bitcoincore_rpc::{json::GetBlockHeaderResult, Client}, @@ -30,7 +30,7 @@ use { }, }; -pub(crate) use self::entry::RuneEntry; +pub use self::entry::RuneEntry; pub(crate) mod entry; mod fetcher; @@ -855,29 +855,10 @@ impl Index { ) } - pub(crate) fn rune(&self, rune: Rune) -> Result> { - let rtx = self.database.begin_read()?; - - let Some(id) = rtx - .open_table(RUNE_TO_RUNE_ID)? - .get(rune.0)? - .map(|guard| guard.value()) - else { - return Ok(None); - }; - - let entry = RuneEntry::load( - rtx - .open_table(RUNE_ID_TO_RUNE_ENTRY)? - .get(id)? - .unwrap() - .value(), - ); - - Ok(Some((RuneId::load(id), entry))) - } - - pub(crate) fn rune_html(&self, rune: Rune) -> Result> { + pub(crate) fn rune( + &self, + rune: Rune, + ) -> Result)>> { let rtx = self.database.begin_read()?; let Some(id) = rtx @@ -907,11 +888,7 @@ impl Index { .is_some() .then_some(parent); - Ok(Some(RuneHtml { - entry, - id: RuneId::load(id), - parent, - })) + Ok(Some((RuneId::load(id), entry, parent))) } pub(crate) fn runes(&self) -> Result> { diff --git a/src/index/entry.rs b/src/index/entry.rs index 8fe5e57516..116ee448ea 100644 --- a/src/index/entry.rs +++ b/src/index/entry.rs @@ -29,20 +29,20 @@ impl Entry for Header { } #[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)] -pub(crate) struct RuneEntry { - pub(crate) burned: u128, - pub(crate) deadline: Option, - pub(crate) divisibility: u8, - pub(crate) end: Option, - pub(crate) etching: Txid, - pub(crate) limit: Option, - pub(crate) mints: u64, - pub(crate) number: u64, - pub(crate) rune: Rune, - pub(crate) spacers: u32, - pub(crate) supply: u128, - pub(crate) symbol: Option, - pub(crate) timestamp: u32, +pub struct RuneEntry { + pub burned: u128, + pub deadline: Option, + pub divisibility: u8, + pub end: Option, + pub etching: Txid, + pub limit: Option, + pub mints: u64, + pub number: u64, + pub rune: Rune, + pub spacers: u32, + pub supply: u128, + pub symbol: Option, + pub timestamp: u32, } pub(super) type RuneEntryValue = ( diff --git a/src/lib.rs b/src/lib.rs index 55b2379d9d..9102594701 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ use { deserialize_from_str::DeserializeFromStr, epoch::Epoch, height::Height, - index::{List, RuneEntry}, + index::List, inscriptions::{media, teleburn, Charm, Media, ParsedEnvelope}, outgoing::Outgoing, representation::Representation, @@ -85,7 +85,7 @@ use { pub use self::{ chain::Chain, fee_rate::FeeRate, - index::Index, + index::{Index, RuneEntry}, inscriptions::{Envelope, Inscription, InscriptionId}, object::Object, options::Options, diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index bf542736b7..03bdaf58fb 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -14,7 +14,7 @@ use { InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson, PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml, PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml, PreviewVideoHtml, - RangeHtml, RareTxt, RuneJson, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, + RangeHtml, RareTxt, RuneHtml, RuneJson, RunesHtml, RunesJson, SatHtml, SatInscriptionJson, SatInscriptionsJson, SatJson, TransactionHtml, }, }, @@ -625,14 +625,14 @@ impl Server { )); } + let (id, entry, parent) = index + .rune(spaced_rune.rune)? + .ok_or_not_found(|| format!("rune {spaced_rune}"))?; + Ok(if accept_json { - Json(index - .rune_html(spaced_rune.rune)?).into_response() - .into_response() + Json(RuneJson { entry, id, parent }).into_response() } else { - index - .rune_html(spaced_rune.rune)? - .ok_or_not_found(|| format!("rune {spaced_rune}"))? + RuneHtml { entry, id, parent } .page(server_config) .into_response() }) diff --git a/src/subcommand/wallet/etch.rs b/src/subcommand/wallet/etch.rs index b02ea68015..1c00a36370 100644 --- a/src/subcommand/wallet/etch.rs +++ b/src/subcommand/wallet/etch.rs @@ -16,6 +16,7 @@ pub(crate) struct Etch { #[derive(Serialize, Deserialize, Debug)] pub struct Output { + pub rune: SpacedRune, pub transaction: Txid, } @@ -123,6 +124,9 @@ impl Etch { let transaction = client.send_raw_transaction(&signed_transaction)?; - Ok(Box::new(Output { transaction })) + Ok(Box::new(Output { + rune: self.rune, + transaction, + })) } } diff --git a/src/subcommand/wallet/send.rs b/src/subcommand/wallet/send.rs index 24575ceac2..bf1d98b0c4 100644 --- a/src/subcommand/wallet/send.rs +++ b/src/subcommand/wallet/send.rs @@ -182,7 +182,7 @@ impl Send { Self::lock_non_cardinal_outputs(client, &inscriptions, &runic_outputs, unspent_outputs)?; - let (id, entry) = index + let (id, entry, _parent) = index .rune(spaced_rune.rune)? .with_context(|| format!("rune `{}` has not been etched", spaced_rune.rune))?; diff --git a/src/templates.rs b/src/templates.rs index b4df720f6e..fc9385d7b7 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -44,8 +44,8 @@ pub mod output; mod preview; mod range; mod rare; -mod rune; -mod runes; +pub mod rune; +pub mod runes; pub mod sat; pub mod status; mod transaction; diff --git a/src/templates/rune.rs b/src/templates/rune.rs index 048d416fd7..78a688a66a 100644 --- a/src/templates/rune.rs +++ b/src/templates/rune.rs @@ -1,12 +1,12 @@ use super::*; -pub(crate) type RuneJson = RuneHtml; +pub type RuneJson = RuneHtml; #[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)] -pub(crate) struct RuneHtml { - pub(crate) entry: RuneEntry, - pub(crate) id: RuneId, - pub(crate) parent: Option, +pub struct RuneHtml { + pub entry: RuneEntry, + pub id: RuneId, + pub parent: Option, } impl PageContent for RuneHtml { diff --git a/src/templates/runes.rs b/src/templates/runes.rs index d7334ad0b6..ace35fca32 100644 --- a/src/templates/runes.rs +++ b/src/templates/runes.rs @@ -1,10 +1,10 @@ use super::*; -pub(crate) type RunesJson = RunesHtml; +pub type RunesJson = RunesHtml; #[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)] -pub(crate) struct RunesHtml { - pub(crate) entries: Vec<(RuneId, RuneEntry)>, +pub struct RunesHtml { + pub entries: Vec<(RuneId, RuneEntry)>, } impl PageContent for RunesHtml { diff --git a/tests/json_api.rs b/tests/json_api.rs index 2be51014f4..b75587eaa2 100644 --- a/tests/json_api.rs +++ b/tests/json_api.rs @@ -369,9 +369,13 @@ fn get_block() { #[test] fn get_status() { let rpc_server = test_bitcoincore_rpc::spawn(); + // .network(Network::Regtest) + // .build(); create_wallet(&rpc_server); + rpc_server.mine_blocks(1); + inscribe(&rpc_server); let response = @@ -397,7 +401,7 @@ fn get_status() { blessed_inscriptions: 1, cursed_inscriptions: 0, chain: Chain::Mainnet, - height: Some(2), + height: Some(3), inscriptions: 1, lost_sats: 0, minimum_rune_for_next_block: Rune(99246114928149462), @@ -411,3 +415,133 @@ fn get_status() { } ); } + +#[test] +fn get_runes() { + let rpc_server = test_bitcoincore_rpc::builder() + .network(Network::Regtest) + .build(); + + create_wallet(&rpc_server); + rpc_server.mine_blocks(3); + + let a = etch(&rpc_server, Rune(RUNE)); + let b = etch(&rpc_server, Rune(RUNE + 1)); + let c = etch(&rpc_server, Rune(RUNE + 2)); + + rpc_server.mine_blocks(1); + + let server = TestServer::spawn_with_server_args( + &rpc_server, + &["--index-runes", "--regtest"], + &["--enable-json-api"], + ); + + let response = server.json_request(format!("/rune/{}", a.rune)); + assert_eq!(response.status(), StatusCode::OK); + + let rune_json: RuneJson = serde_json::from_str(&response.text().unwrap()).unwrap(); + + pretty_assert_eq!( + rune_json, + RuneJson { + entry: RuneEntry { + burned: 0, + deadline: None, + divisibility: 0, + end: None, + etching: a.transaction, + limit: None, + mints: 0, + number: 0, + rune: Rune(RUNE), + spacers: 0, + supply: 1000, + symbol: Some('¢'), + timestamp: 5, + }, + id: RuneId { + height: 5, + index: 1 + }, + parent: None, + } + ); + + let response = server.json_request("/runes"); + + assert_eq!(response.status(), StatusCode::OK); + + let runes_json: RunesJson = serde_json::from_str(&response.text().unwrap()).unwrap(); + + pretty_assert_eq!( + runes_json, + RunesJson { + entries: vec![ + ( + RuneId { + height: 5, + index: 1 + }, + RuneEntry { + burned: 0, + deadline: None, + divisibility: 0, + end: None, + etching: a.transaction, + limit: None, + mints: 0, + number: 0, + rune: Rune(RUNE), + spacers: 0, + supply: 1000, + symbol: Some('¢'), + timestamp: 5, + } + ), + ( + RuneId { + height: 7, + index: 1 + }, + RuneEntry { + burned: 0, + deadline: None, + divisibility: 0, + end: None, + etching: b.transaction, + limit: None, + mints: 0, + number: 1, + rune: Rune(RUNE + 1), + spacers: 0, + supply: 1000, + symbol: Some('¢'), + timestamp: 7, + } + ), + ( + RuneId { + height: 9, + index: 1 + }, + RuneEntry { + burned: 0, + deadline: None, + divisibility: 0, + end: None, + etching: c.transaction, + limit: None, + mints: 0, + number: 2, + rune: Rune(RUNE + 2), + spacers: 0, + supply: 1000, + symbol: Some('¢'), + timestamp: 9, + } + ) + ] + } + ); +} diff --git a/tests/lib.rs b/tests/lib.rs index 0942ad1acf..bf0042c024 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -15,9 +15,9 @@ use { subcommand::runes::RuneInfo, templates::{ block::BlockJson, inscription::InscriptionJson, inscriptions::InscriptionsJson, - output::OutputJson, sat::SatJson, status::StatusHtml, + output::OutputJson, rune::RuneJson, runes::RunesJson, sat::SatJson, status::StatusHtml, }, - Edict, InscriptionId, Rune, RuneId, Runestone, SatPoint, + Edict, InscriptionId, Rune, RuneEntry, RuneId, Runestone, SatPoint, }, pretty_assertions::assert_eq as pretty_assert_eq, regex::Regex, diff --git a/tests/test_server.rs b/tests/test_server.rs index 87a7f794cc..0eff05d8ff 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -27,18 +27,19 @@ impl TestServer { server_args: &[&str], ) -> Self { let tempdir = TempDir::new().unwrap(); - fs::write(tempdir.path().join(".cookie"), "foo:bar").unwrap(); + let cookie_file = tempdir.path().join(".cookie"); + fs::write(cookie_file.clone(), "foo:bar").unwrap(); let port = TcpListener::bind("127.0.0.1:0") .unwrap() .local_addr() .unwrap() .port(); - let child = Command::new(executable_path("ord")).args(format!( - "--rpc-url {} --bitcoin-data-dir {} --data-dir {} {} server {} --http-port {port} --address 127.0.0.1", + "--rpc-url {} --bitcoin-data-dir {} --data-dir {} --cookie-file {} {} server {} --http-port {port} --address 127.0.0.1", rpc_server.url(), tempdir.path().display(), tempdir.path().display(), + cookie_file.display(), ord_args.join(" "), server_args.join(" "), ).to_args()) From 0de93c8ece21ba4c225199e45f16c9f969d2e020 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Thu, 4 Jan 2024 23:04:27 +0100 Subject: [PATCH 11/12] Fix test --- tests/json_api.rs | 24 +++++++++++++----------- tests/lib.rs | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/tests/json_api.rs b/tests/json_api.rs index b75587eaa2..b567024f16 100644 --- a/tests/json_api.rs +++ b/tests/json_api.rs @@ -368,19 +368,21 @@ fn get_block() { #[test] fn get_status() { - let rpc_server = test_bitcoincore_rpc::spawn(); - // .network(Network::Regtest) - // .build(); + let rpc_server = test_bitcoincore_rpc::builder() + .network(Network::Regtest) + .build(); create_wallet(&rpc_server); - rpc_server.mine_blocks(1); - inscribe(&rpc_server); + inscribe_regtest(&rpc_server); - let response = - TestServer::spawn_with_server_args(&rpc_server, &["--index-sats"], &["--enable-json-api"]) - .json_request("/status"); + let response = TestServer::spawn_with_server_args( + &rpc_server, + &["--regtest", "--index-sats", "--index-runes"], + &["--enable-json-api"], + ) + .json_request("/status"); assert_eq!(response.status(), StatusCode::OK); @@ -400,12 +402,12 @@ fn get_status() { StatusHtml { blessed_inscriptions: 1, cursed_inscriptions: 0, - chain: Chain::Mainnet, + chain: Chain::Regtest, height: Some(3), inscriptions: 1, lost_sats: 0, - minimum_rune_for_next_block: Rune(99246114928149462), - rune_index: false, + minimum_rune_for_next_block: Rune(99218849511960410), + rune_index: true, runes: 0, sat_index: true, started: dummy_started, diff --git a/tests/lib.rs b/tests/lib.rs index bf0042c024..c0275b9d26 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -120,6 +120,21 @@ fn inscribe(rpc_server: &test_bitcoincore_rpc::Handle) -> (InscriptionId, Txid) (output.inscriptions[0].id, output.reveal) } +fn inscribe_regtest(rpc_server: &test_bitcoincore_rpc::Handle) -> (InscriptionId, Txid) { + rpc_server.mine_blocks(1); + + let output = CommandBuilder::new("--regtest wallet inscribe --fee-rate 1 --file foo.txt") + .write("foo.txt", "FOO") + .rpc_server(rpc_server) + .run_and_deserialize_output::(); + + rpc_server.mine_blocks(1); + + assert_eq!(output.inscriptions.len(), 1); + + (output.inscriptions[0].id, output.reveal) +} + mod command_builder; mod expected; mod test_server; From 3ddc2338a0aad56b8e12afdd04736f1031317238 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Fri, 5 Jan 2024 00:24:53 +0100 Subject: [PATCH 12/12] Fix nits --- tests/json_api.rs | 2 +- tests/lib.rs | 26 +++++++------------------- tests/test_server.rs | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/tests/json_api.rs b/tests/json_api.rs index b567024f16..439e440835 100644 --- a/tests/json_api.rs +++ b/tests/json_api.rs @@ -375,7 +375,7 @@ fn get_status() { create_wallet(&rpc_server); rpc_server.mine_blocks(1); - inscribe_regtest(&rpc_server); + inscribe(&rpc_server); let response = TestServer::spawn_with_server_args( &rpc_server, diff --git a/tests/lib.rs b/tests/lib.rs index c0275b9d26..f1d3ad25a4 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -108,25 +108,13 @@ fn runes(rpc_server: &test_bitcoincore_rpc::Handle) -> BTreeMap fn inscribe(rpc_server: &test_bitcoincore_rpc::Handle) -> (InscriptionId, Txid) { rpc_server.mine_blocks(1); - let output = CommandBuilder::new("wallet inscribe --fee-rate 1 --file foo.txt") - .write("foo.txt", "FOO") - .rpc_server(rpc_server) - .run_and_deserialize_output::(); - - rpc_server.mine_blocks(1); - - assert_eq!(output.inscriptions.len(), 1); - - (output.inscriptions[0].id, output.reveal) -} - -fn inscribe_regtest(rpc_server: &test_bitcoincore_rpc::Handle) -> (InscriptionId, Txid) { - rpc_server.mine_blocks(1); - - let output = CommandBuilder::new("--regtest wallet inscribe --fee-rate 1 --file foo.txt") - .write("foo.txt", "FOO") - .rpc_server(rpc_server) - .run_and_deserialize_output::(); + let output = CommandBuilder::new(format!( + "--chain {} wallet inscribe --fee-rate 1 --file foo.txt", + rpc_server.network() + )) + .write("foo.txt", "FOO") + .rpc_server(rpc_server) + .run_and_deserialize_output::(); rpc_server.mine_blocks(1); diff --git a/tests/test_server.rs b/tests/test_server.rs index 0eff05d8ff..7541264411 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -27,19 +27,28 @@ impl TestServer { server_args: &[&str], ) -> Self { let tempdir = TempDir::new().unwrap(); - let cookie_file = tempdir.path().join(".cookie"); + + let cookie_file = match rpc_server.network().as_str() { + "mainnet" => tempdir.path().join(".cookie"), + network => { + fs::create_dir(tempdir.path().join(network)).unwrap(); + tempdir.path().join(format!("{network}/.cookie")) + } + }; + fs::write(cookie_file.clone(), "foo:bar").unwrap(); + let port = TcpListener::bind("127.0.0.1:0") .unwrap() .local_addr() .unwrap() .port(); + let child = Command::new(executable_path("ord")).args(format!( - "--rpc-url {} --bitcoin-data-dir {} --data-dir {} --cookie-file {} {} server {} --http-port {port} --address 127.0.0.1", + "--rpc-url {} --bitcoin-data-dir {} --data-dir {} {} server {} --http-port {port} --address 127.0.0.1", rpc_server.url(), tempdir.path().display(), tempdir.path().display(), - cookie_file.display(), ord_args.join(" "), server_args.join(" "), ).to_args())