Skip to content

Commit

Permalink
Add /runes/balances (#2978)
Browse files Browse the repository at this point in the history
  • Loading branch information
lugondev authored Jan 31, 2024
1 parent 13c0fa1 commit d829fd2
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 10 deletions.
31 changes: 25 additions & 6 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use {
InscriptionsBlockHtml, InscriptionsHtml, InscriptionsJson, OutputHtml, OutputJson,
PageContent, PageHtml, PreviewAudioHtml, PreviewCodeHtml, PreviewFontHtml, PreviewImageHtml,
PreviewMarkdownHtml, PreviewModelHtml, PreviewPdfHtml, PreviewTextHtml, PreviewUnknownHtml,
PreviewVideoHtml, RangeHtml, RareTxt, RuneHtml, RuneJson, RunesHtml, RunesJson, SatHtml,
SatInscriptionJson, SatInscriptionsJson, SatJson, TransactionHtml, TransactionJson,
PreviewVideoHtml, RangeHtml, RareTxt, RuneBalancesHtml, RuneHtml, RuneJson, RunesHtml,
RunesJson, SatHtml, SatInscriptionJson, SatInscriptionsJson, SatJson, TransactionHtml,
TransactionJson,
},
},
axum::{
Expand Down Expand Up @@ -274,6 +275,7 @@ impl Server {
.route("/rare.txt", get(Self::rare_txt))
.route("/rune/:rune", get(Self::rune))
.route("/runes", get(Self::runes))
.route("/runes/balances", get(Self::runes_balances))
.route("/sat/:sat", get(Self::sat))
.route("/search", get(Self::search_by_query))
.route("/search/*query", get(Self::search_by_path))
Expand Down Expand Up @@ -685,6 +687,23 @@ impl Server {
})
}

async fn runes_balances(
Extension(server_config): Extension<Arc<ServerConfig>>,
Extension(index): Extension<Arc<Index>>,
AcceptJson(accept_json): AcceptJson,
) -> ServerResult<Response> {
task::block_in_place(|| {
let balances = index.get_rune_balance_map()?;
Ok(if accept_json {
Json(balances).into_response()
} else {
RuneBalancesHtml { balances }
.page(server_config)
.into_response()
})
})
}

async fn home(
Extension(server_config): Extension<Arc<ServerConfig>>,
Extension(index): Extension<Arc<Index>>,
Expand Down Expand Up @@ -805,11 +824,11 @@ impl Server {
.into_response()
} else {
TransactionHtml {
transaction,
txid,
inscription_count,
chain: server_config.chain,
etching: index.get_etching(txid)?,
inscription_count,
transaction,
txid,
}
.page(server_config)
.into_response()
Expand Down Expand Up @@ -2812,7 +2831,7 @@ mod tests {
TestServer::new().assert_response_regex(
"/range/0/1",
StatusCode::OK,
r".*<title>Sat range 0–1</title>.*<h1>Sat range 0–1</h1>
r".*<title>Sat Range 0–1</title>.*<h1>Sat Range 0–1</h1>
<dl>
<dt>value</dt><dd>1</dd>
<dt>first</dt><dd><a href=/sat/0 class=mythic>0</a></dd>
Expand Down
2 changes: 2 additions & 0 deletions src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub(crate) use {
range::RangeHtml,
rare::RareTxt,
rune::{RuneHtml, RuneJson},
rune_balances::RuneBalancesHtml,
runes::{RunesHtml, RunesJson},
sat::{SatHtml, SatInscriptionJson, SatInscriptionsJson, SatJson},
server_config::ServerConfig,
Expand All @@ -45,6 +46,7 @@ mod preview;
mod range;
mod rare;
pub mod rune;
pub mod rune_balances;
pub mod runes;
pub mod sat;
pub mod status;
Expand Down
6 changes: 3 additions & 3 deletions src/templates/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) struct RangeHtml {

impl PageContent for RangeHtml {
fn title(&self) -> String {
format!("Sat range {}–{}", self.start, self.end)
format!("Sat Range {}–{}", self.start, self.end)
}
}

Expand All @@ -25,7 +25,7 @@ mod tests {
}
.to_string(),
"
<h1>Sat range 0–1</h1>
<h1>Sat Range 0–1</h1>
<dl>
<dt>value</dt><dd>1</dd>
<dt>first</dt><dd><a href=/sat/0 class=mythic>0</a></dd>
Expand All @@ -44,7 +44,7 @@ mod tests {
}
.to_string(),
"
<h1>Sat range 1–10</h1>
<h1>Sat Range 1–10</h1>
<dl>
<dt>value</dt><dd>9</dd>
<dt>first</dt><dd><a href=/sat/1 class=common>1</a></dd>
Expand Down
94 changes: 94 additions & 0 deletions src/templates/rune_balances.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use super::*;

#[derive(Boilerplate, Debug, PartialEq, Serialize, Deserialize)]
pub struct RuneBalancesHtml {
pub balances: BTreeMap<Rune, BTreeMap<OutPoint, u128>>,
}

impl PageContent for RuneBalancesHtml {
fn title(&self) -> String {
"Rune Balances".to_string()
}
}

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

const RUNE: u128 = 99246114928149462;

#[test]
fn display_rune_balances() {
let balances: BTreeMap<Rune, BTreeMap<OutPoint, u128>> = vec![
(
Rune(RUNE),
vec![(
OutPoint {
txid: txid(1),
vout: 1,
},
1000,
)]
.into_iter()
.collect(),
),
(
Rune(RUNE + 1),
vec![(
OutPoint {
txid: txid(2),
vout: 2,
},
12345678,
)]
.into_iter()
.collect(),
),
]
.into_iter()
.collect();

assert_regex_match!(
RuneBalancesHtml { balances }.to_string(),
"<h1>Rune Balances</h1>
<table>
<tr>
<th>rune</th>
<th>balances</th>
</tr>
<tr>
<td><a href=/rune/AAAAAAAAAAAAA>.*</a></td>
<td>
<table>
<tr>
<td class=monospace>
<a href=/output/1{64}:1>1{64}:1</a>
</td>
<td class=monospace>
1000
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td><a href=/rune/AAAAAAAAAAAAB>.*</a></td>
<td>
<table>
<tr>
<td class=monospace>
<a href=/output/2{64}:2>2{64}:2</a>
</td>
<td class=monospace>
12345678
</td>
</tr>
</table>
</td>
</tr>
</table>
"
.unindent()
);
}
}
2 changes: 1 addition & 1 deletion templates/range.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1>Sat range {{self.start}}–{{self.end}}</h1>
<h1>Sat Range {{self.start}}–{{self.end}}</h1>
<dl>
<dt>value</dt><dd>{{self.end.n() - self.start.n()}}</dd>
<dt>first</dt><dd><a href=/sat/{{self.start.n()}} class={{self.start.rarity()}}>{{self.start.n()}}</a></dd>
Expand Down
26 changes: 26 additions & 0 deletions templates/rune-balances.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<h1>Rune Balances</h1>
<table>
<tr>
<th>rune</th>
<th>balances</th>
</tr>
%% for (rune, balances) in &self.balances {
<tr>
<td><a href=/rune/{{ rune }}>{{ rune }}</a></td>
<td>
<table>
%% for (outpoint, balance) in balances {
<tr>
<td class=monospace>
<a href=/output/{{ outpoint }}>{{ outpoint }}</a>
</td>
<td class=monospace>
{{ balance }}
</td>
</tr>
%% }
</table>
</td>
</tr>
%% }
</table>
72 changes: 72 additions & 0 deletions tests/json_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,75 @@ fn get_runes() {
}
);
}
#[test]
fn get_runes_balances() {
let bitcoin_rpc_server = test_bitcoincore_rpc::builder()
.network(Network::Regtest)
.build();

let ord_rpc_server =
TestServer::spawn_with_server_args(&bitcoin_rpc_server, &["--index-runes", "--regtest"], &[]);

create_wallet(&bitcoin_rpc_server, &ord_rpc_server);

bitcoin_rpc_server.mine_blocks(3);

let rune0 = Rune(RUNE);
let rune1 = Rune(RUNE + 1);
let rune2 = Rune(RUNE + 2);

let e0 = etch(&bitcoin_rpc_server, &ord_rpc_server, rune0);
let e1 = etch(&bitcoin_rpc_server, &ord_rpc_server, rune1);
let e2 = etch(&bitcoin_rpc_server, &ord_rpc_server, rune2);

bitcoin_rpc_server.mine_blocks(1);

let rune_balances: BTreeMap<Rune, BTreeMap<OutPoint, u128>> = vec![
(
rune0,
vec![(
OutPoint {
txid: e0.transaction,
vout: 1,
},
1000,
)]
.into_iter()
.collect(),
),
(
rune1,
vec![(
OutPoint {
txid: e1.transaction,
vout: 1,
},
1000,
)]
.into_iter()
.collect(),
),
(
rune2,
vec![(
OutPoint {
txid: e2.transaction,
vout: 1,
},
1000,
)]
.into_iter()
.collect(),
),
]
.into_iter()
.collect();

let response = ord_rpc_server.json_request("/runes/balances");
assert_eq!(response.status(), StatusCode::OK);

let runes_balance_json: BTreeMap<Rune, BTreeMap<OutPoint, u128>> =
serde_json::from_str(&response.text().unwrap()).unwrap();

pretty_assert_eq!(runes_balance_json, rune_balances);
}

0 comments on commit d829fd2

Please sign in to comment.