Skip to content

Commit

Permalink
List block transactions at /block/:hash (ordinals#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
terror committed Aug 5, 2022
1 parent 714a332 commit 65113c3
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 6 deletions.
14 changes: 12 additions & 2 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl Index {
.map(|(height, _hash)| height + 1)
.unwrap_or(0);

let block = match self.block(height)? {
let block = match self.block_at_height(height)? {
Some(block) => block,
None => {
return Ok(true);
Expand Down Expand Up @@ -295,7 +295,7 @@ impl Index {
Ok(())
}

pub(crate) fn block(&self, height: u64) -> Result<Option<Block>> {
pub(crate) fn block_at_height(&self, height: u64) -> Result<Option<Block>> {
match self.client.get_block_hash(height) {
Ok(hash) => Ok(Some(self.client.get_block(&hash)?)),
Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc(
Expand All @@ -305,6 +305,16 @@ impl Index {
}
}

pub(crate) fn block_with_hash(&self, hash: sha256d::Hash) -> Result<Option<Block>> {
match self.client.get_block(&BlockHash::from_hash(hash)) {
Ok(block) => Ok(Some(block)),
Err(bitcoincore_rpc::Error::JsonRpc(bitcoincore_rpc::jsonrpc::error::Error::Rpc(
bitcoincore_rpc::jsonrpc::error::RpcError { code: -8, .. },
))) => Ok(None),
Err(err) => Err(err.into()),
}
}

pub(crate) fn find(&self, ordinal: Ordinal) -> Result<Option<SatPoint>> {
if self.height()? <= ordinal.height().0 {
return Ok(None);
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use {
bitcoin::{
blockdata::constants::COIN_VALUE,
consensus::{Decodable, Encodable},
hash_types::BlockHash,
hashes::{sha256, sha256d, Hash, HashEngine},
secp256k1::{
self,
Expand Down
46 changes: 45 additions & 1 deletion src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl Server {

let app = Router::new()
.route("/", get(Self::root))
.route("/block/:hash", get(Self::block))
.route("/ordinal/:ordinal", get(Self::ordinal))
.route("/list/:outpoint", get(Self::list))
.route("/status", get(Self::status))
Expand Down Expand Up @@ -143,7 +144,9 @@ impl Server {
blocks
.iter()
.enumerate()
.map(|(height, hash)| format!(" <li>{height} - {hash}</li>\n"))
.map(|(height, hash)| format!(
" <li>{height} - <a href='/block/{hash}'>{hash}</a></li>\n"
))
.collect::<String>(),
)),
),
Expand All @@ -162,6 +165,47 @@ impl Server {
}
}

async fn block(
extract::Path(hash): extract::Path<sha256d::Hash>,
index: extract::Extension<Arc<Index>>,
) -> impl IntoResponse {
match index.block_with_hash(hash) {
Ok(Some(block)) => (
StatusCode::OK,
Html(format!(
"<ul>\n{}</ul>",
block
.txdata
.iter()
.enumerate()
.map(|(i, tx)| format!(" <li>{i} - {}</li>\n", tx.txid()))
.collect::<String>()
)),
),
Ok(None) => (
StatusCode::NOT_FOUND,
Html(
StatusCode::NOT_FOUND
.canonical_reason()
.unwrap_or_default()
.to_string(),
),
),
Err(error) => {
eprintln!("Error serving request for block with hash {hash}: {error}");
(
StatusCode::INTERNAL_SERVER_ERROR,
Html(
StatusCode::INTERNAL_SERVER_ERROR
.canonical_reason()
.unwrap_or_default()
.to_string(),
),
)
}
}
}

async fn list(
extract::Path(outpoint): extract::Path<OutPoint>,
index: extract::Extension<Arc<Index>>,
Expand Down
4 changes: 3 additions & 1 deletion tests/rpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ impl RpcApi for RpcServer {
}
}

panic!("No block with hash {blockhash}")
Err(jsonrpc_core::Error::new(
jsonrpc_core::types::error::ErrorCode::ServerError(-8),
))
}
}
43 changes: 41 additions & 2 deletions tests/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,53 @@ fn root() -> Result {
200,
"
<ul>
<li>0 - 14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b</li>
<li>1 - 467a86f0642b1d284376d13a98ef58310caa49502b0f9a560ee222e0a122fe16</li>
<li>0 - <a href='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/block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b'>14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b</a></li>
<li>1 - <a href='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/block/467a86f0642b1d284376d13a98ef58310caa49502b0f9a560ee222e0a122fe16'>467a86f0642b1d284376d13a98ef58310caa49502b0f9a560ee222e0a122fe16</a></li>
</ul>
",
)
.run_server(port)
}

#[test]
fn transactions() -> Result {
let port = free_port()?;

Test::new()?
.command(&format!("server --address 127.0.0.1 --http-port {port}"))
.block()
.transaction(TransactionOptions {
slots: &[(0, 0, 0)],
output_count: 1,
fee: 0,
})
.request(
"block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b",
200,
"
<ul>
<li>0 - 0396bc915f141f7de025f72ae9b6bb8dcdb5f444fc245d8fac486ba67a38eef9</li>
<li>1 - d0a9c70e6c8d890ee5883973a716edc1609eab42a9bc32594bdafc935bb4fad0</li>
</ul>
",
)
.run_server(port)
}

#[test]
fn block_not_found() -> Result {
let port = free_port()?;

Test::new()?
.command(&format!("server --address 127.0.0.1 --http-port {port}"))
.request(
"block/14508459b221041eab257d2baaa7459775ba748246c8403609eb708f0e57e74b",
404,
"Not Found",
)
.run_server(port)
}

#[test]
fn http_or_https_port_is_required() -> Result {
Test::new()?
Expand Down

0 comments on commit 65113c3

Please sign in to comment.