Skip to content

Commit

Permalink
Add /satpoint/<SATPOINT> endpoint (#3949)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphjaph authored Sep 16, 2024
1 parent b3f5add commit 5ecc1d4
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 130 deletions.
106 changes: 106 additions & 0 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ impl Server {
.route("/runes/:page", get(Self::runes_paginated))
.route("/runes/balances", get(Self::runes_balances))
.route("/sat/:sat", get(Self::sat))
.route("/satpoint/:satpoint", get(Self::satpoint))
.route("/search", get(Self::search_by_query))
.route("/search/*query", get(Self::search_by_path))
.route("/static/*path", get(Self::static_asset))
Expand Down Expand Up @@ -610,6 +611,36 @@ impl Server {
})
}

async fn satpoint(
Extension(index): Extension<Arc<Index>>,
Path(satpoint): Path<SatPoint>,
) -> ServerResult<Redirect> {
task::block_in_place(|| {
let (output_info, _) = index
.get_output_info(satpoint.outpoint)?
.ok_or_not_found(|| format!("satpoint {satpoint}"))?;

let Some(ranges) = output_info.sat_ranges else {
return Err(ServerError::NotFound("sat index required".into()));
};

let mut total = 0;
for (start, end) in ranges {
let size = end - start;
if satpoint.offset < total + size {
let sat = start + satpoint.offset - total;

return Ok(Redirect::to(&format!("/sat/{sat}")));
}
total += size;
}

Err(ServerError::NotFound(format!(
"satpoint {satpoint} not found"
)))
})
}

async fn outputs(
Extension(index): Extension<Arc<Index>>,
AcceptJson(accept_json): AcceptJson,
Expand Down Expand Up @@ -1144,6 +1175,8 @@ impl Server {
Ok(Redirect::to(&format!("/rune/{rune}")))
} else if re::ADDRESS.is_match(query) {
Ok(Redirect::to(&format!("/address/{query}")))
} else if re::SATPOINT.is_match(query) {
Ok(Redirect::to(&format!("/satpoint/{query}")))
} else {
Ok(Redirect::to(&format!("/sat/{query}")))
}
Expand Down Expand Up @@ -2815,6 +2848,79 @@ mod tests {
);
}

#[test]
fn search_by_satpoint_returns_sat() {
let server = TestServer::builder()
.chain(Chain::Regtest)
.index_sats()
.build();

let txid = server.mine_blocks(1)[0].txdata[0].txid();

server.assert_redirect(
&format!("/search/{txid}:0:0"),
&format!("/satpoint/{txid}:0:0"),
);

server.assert_redirect(
&format!("/search?query={txid}:0:0"),
&format!("/satpoint/{txid}:0:0"),
);

server.assert_redirect(
&format!("/satpoint/{txid}:0:0"),
&format!("/sat/{}", 50 * COIN_VALUE),
);

server.assert_response_regex("/search/1:2:3", StatusCode::BAD_REQUEST, ".*");
}

#[test]
fn satpoint_returns_sat_in_multiple_ranges() {
let server = TestServer::builder()
.chain(Chain::Regtest)
.index_sats()
.build();

server.mine_blocks(1);

let split = TransactionTemplate {
inputs: &[(1, 0, 0, Default::default())],
outputs: 2,
fee: 0,
..default()
};

server.core.broadcast_tx(split);

server.mine_blocks(1);

let merge = TransactionTemplate {
inputs: &[(2, 0, 0, Default::default()), (2, 1, 0, Default::default())],
fee: 0,
..default()
};

let txid = server.core.broadcast_tx(merge);

server.mine_blocks(1);

server.assert_redirect(
&format!("/satpoint/{txid}:0:0"),
&format!("/sat/{}", 100 * COIN_VALUE),
);

server.assert_redirect(
&format!("/satpoint/{txid}:0:{}", 50 * COIN_VALUE),
&format!("/sat/{}", 50 * COIN_VALUE),
);

server.assert_redirect(
&format!("/satpoint/{txid}:0:{}", 50 * COIN_VALUE - 1),
&format!("/sat/{}", 150 * COIN_VALUE - 1),
);
}

#[test]
fn html_runes_balances_not_found() {
TestServer::builder()
Expand Down
10 changes: 5 additions & 5 deletions src/templates/inscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ mod tests {
<dt>reveal transaction</dt>
<dd><a class=monospace href=/tx/1{64}>1{64}</a></dd>
<dt>location</dt>
<dd class=monospace>1{64}:1:0</dd>
<dd><a class=monospace href=/satpoint/1{64}:1:0>1{64}:1:0</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/1{64}:1>1{64}:1</a></dd>
<dt>offset</dt>
Expand Down Expand Up @@ -193,7 +193,7 @@ mod tests {
<dl>
.*
<dt>location</dt>
<dd class=monospace>0{64}:0:0</dd>
<dd><a class=monospace href=/satpoint/0{64}:0:0>0{64}:0:0</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/0{64}:0>0{64}:0</a></dd>
.*
Expand Down Expand Up @@ -251,7 +251,7 @@ mod tests {
<dt>reveal transaction</dt>
<dd><a class=monospace href=/tx/1{64}>1{64}</a></dd>
<dt>location</dt>
<dd class=monospace>1{64}:1:0</dd>
<dd><a class=monospace href=/satpoint/1{64}:1:0>1{64}:1:0</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/1{64}:1>1{64}:1</a></dd>
<dt>offset</dt>
Expand Down Expand Up @@ -313,7 +313,7 @@ mod tests {
<dt>reveal transaction</dt>
<dd><a class=monospace href=/tx/1{64}>1{64}</a></dd>
<dt>location</dt>
<dd class=monospace>1{64}:1:0</dd>
<dd><a class=monospace href=/satpoint/1{64}:1:0>1{64}:1:0</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/1{64}:1>1{64}:1</a></dd>
<dt>offset</dt>
Expand Down Expand Up @@ -374,7 +374,7 @@ mod tests {
<dt>reveal transaction</dt>
<dd><a class=monospace href=/tx/1{64}>1{64}</a></dd>
<dt>location</dt>
<dd class=monospace>1{64}:1:0</dd>
<dd><a class=monospace href=/satpoint/1{64}:1:0>1{64}:1:0</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/1{64}:1>1{64}:1</a></dd>
<dt>offset</dt>
Expand Down
2 changes: 1 addition & 1 deletion templates/inscription.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ <h1>Inscription {{ self.number }}</h1>
<dt>reveal transaction</dt>
<dd><a class=monospace href=/tx/{{ self.id.txid }}>{{ self.id.txid }}</a></dd>
<dt>location</dt>
<dd class=monospace>{{ self.satpoint }}</dd>
<dd><a class=monospace href=/satpoint/{{ self.satpoint }}>{{ self.satpoint }}</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/{{ self.satpoint.outpoint }}>{{ self.satpoint.outpoint }}</a></dd>
<dt>offset</dt>
Expand Down
6 changes: 3 additions & 3 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ fn inscription_page() {
<dt>reveal transaction</dt>
<dd><a class=monospace href=/tx/{reveal}>{reveal}</a></dd>
<dt>location</dt>
<dd class=monospace>{reveal}:0:0</dd>
<dd><a class=monospace href=/satpoint/{reveal}:0:0>{reveal}:0:0</a></dd>
<dt>output</dt>
<dd><a class=monospace href=/output/{reveal}:0>{reveal}:0</a></dd>
<dt>offset</dt>
Expand Down Expand Up @@ -362,7 +362,7 @@ fn inscription_page_after_send() {
ord.assert_response_regex(
format!("/inscription/{inscription}"),
format!(
r".*<h1>Inscription 0</h1>.*<dt>location</dt>\s*<dd class=monospace>{reveal}:0:0</dd>.*",
r".*<h1>Inscription 0</h1>.*<dt>location</dt>\s*<dd><a class=monospace href=/satpoint/{reveal}:0:0>{reveal}:0:0</a></dd>.*",
),
);

Expand All @@ -380,7 +380,7 @@ fn inscription_page_after_send() {
ord.assert_response_regex(
format!("/inscription/{inscription}"),
format!(
r".*<h1>Inscription 0</h1>.*<dt>address</dt>\s*<dd class=monospace><a href=/address/bc1qcqgs2pps4u4yedfyl5pysdjjncs8et5utseepv>bc1qcqgs2pps4u4yedfyl5pysdjjncs8et5utseepv</a></dd>.*<dt>location</dt>\s*<dd class=monospace>{txid}:0:0</dd>.*",
r".*<h1>Inscription 0</h1>.*<dt>address</dt>\s*<dd class=monospace><a href=/address/bc1qcqgs2pps4u4yedfyl5pysdjjncs8et5utseepv>bc1qcqgs2pps4u4yedfyl5pysdjjncs8et5utseepv</a></dd>.*<dt>location</dt>\s*<dd><a class=monospace href=/satpoint/{txid}:0:0>{txid}:0:0</a></dd>.*",
),
)
}
Expand Down
Loading

0 comments on commit 5ecc1d4

Please sign in to comment.