diff --git a/docs/src/guides/api.md b/docs/src/guides/api.md index f53f77afc0..f5dda88ce4 100644 --- a/docs/src/guides/api.md +++ b/docs/src/guides/api.md @@ -5129,4 +5129,4 @@ curl -s -H "Accept: application/json" \ See [Recursion](../inscriptions/recursion.md) for an explanation of these. -{{#include ../inscriptions/recursion.md:35:3429}} +{{#include ../inscriptions/recursion.md:35:3483}} diff --git a/docs/src/inscriptions/recursion.md b/docs/src/inscriptions/recursion.md index 7821476864..8b8c6dd080 100644 --- a/docs/src/inscriptions/recursion.md +++ b/docs/src/inscriptions/recursion.md @@ -3399,6 +3399,30 @@ Hello, world! +
+ + GET + /r/tx/<TRANSACTION_ID> + + +### Description + +Get hex-encoded transaction with ``. In the event of a future +change to Bitcoin that changes transaction serialization in a +backwards-incompatible fashion, such as SegWit, this endpoint is guaranteed to +remain backwards compatible. + +### Example + +```bash +curl -s http://0.0.0.0:80/r/tx/60bcf821240064a9c55225c4f01711b0ebbcab39aa3fafeefe4299ab158536fa +``` + +```json +"0100000000010183572872dcb32bee57003d53c2b8dbb5bc5819ff6478052599911f7778d1c7bd0000000000fdffffff011027000000000000225120e41e0cba05c6ac797cf543ff9a6c619a91a53813e59146d1e32ea89747b111a603407aa50d93d6fc01265fd52d3edc93af4e009ccc1a704ce1b5cb8ede1412a5df31eba587d080b3dc903ceb9002ed9d921aad323fd44d7b4dc2a1ad2ea12d4360424d20c7a3a38df198a4fcde7d5dac5819ed19ff4d25bb893c9511f8e1f51d59326effac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800077072696d65730a6821c1c7a3a38df198a4fcde7d5dac5819ed19ff4d25bb893c9511f8e1f51d59326eff00000000" +``` +
+
GET diff --git a/src/index.rs b/src/index.rs index 390a0ad43d..55541a8198 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1615,6 +1615,19 @@ impl Index { self.client.get_raw_transaction(&txid, None).into_option() } + pub fn get_transaction_hex_recursive(&self, txid: Txid) -> Result> { + if txid == self.genesis_block_coinbase_txid { + return Ok(Some(consensus::encode::serialize_hex( + &self.genesis_block_coinbase_transaction, + ))); + } + + self + .client + .get_raw_transaction_hex(&txid, None) + .into_option() + } + pub fn find(&self, sat: Sat) -> Result> { let sat = sat.0; let rtx = self.begin_read()?; diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 4514a529bc..97da99e408 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -263,6 +263,7 @@ impl Server { "/r/parents/{inscription_id}/{page}", get(Self::parents_recursive_paginated), ) + .route("/r/tx/{txid}", get(Self::get_transaction_hex_recursive)) .route("/r/sat/{sat_number}", get(Self::sat_inscriptions)) .route( "/r/sat/{sat_number}/at/{index}", @@ -1195,6 +1196,19 @@ impl Server { }) } + async fn get_transaction_hex_recursive( + Extension(index): Extension>, + Path(txid): Path, + ) -> ServerResult> { + task::block_in_place(|| { + Ok(Json( + index + .get_transaction_hex_recursive(txid)? + .ok_or_not_found(|| format!("transaction {txid}"))?, + )) + }) + } + async fn decode( Extension(index): Extension>, Path(txid): Path, @@ -4519,6 +4533,33 @@ mod tests { ); } + #[test] + fn recursive_transaction_hex_endpoint() { + let test_server = TestServer::new(); + + let coinbase_tx = test_server.mine_blocks(1)[0].txdata[0].clone(); + let txid = coinbase_tx.compute_txid(); + + test_server.assert_response( + format!("/r/tx/{txid}"), + StatusCode::OK, + "\"02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff0100f2052a01000000225120be7cbbe9ca06a7d7b2a17c6b4ff4b85b362cbcd7ee1970daa66dfaa834df59a000000000\"" + ); + } + + #[test] + fn recursive_transaction_hex_endpoint_for_genesis_transaction() { + let test_server = TestServer::new(); + + test_server.mine_blocks(1); + + test_server.assert_response( + "/r/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", + StatusCode::OK, + "\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000\"" + ); + } + #[test] fn detect_unrecoverable_reorg() { let test_server = TestServer::new();