Skip to content

Commit

Permalink
Add recursive endpoint with more details about children (ordinals#3771)
Browse files Browse the repository at this point in the history
  • Loading branch information
gmart7t2 committed May 30, 2024
1 parent 7ba899a commit 412d37a
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 0 deletions.
40 changes: 40 additions & 0 deletions docs/src/inscriptions/recursion.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ The recursive endpoints are:
- `/r/blocktime`: UNIX time stamp of latest block.
- `/r/children/<INSCRIPTION_ID>`: the first 100 child inscription ids.
- `/r/children/<INSCRIPTION_ID>/<PAGE>`: the set of 100 child inscription ids on `<PAGE>`.
- `/r/children/<INSCRIPTION_ID>/inscriptions`: details of the first 100 child inscriptions.
- `/r/children/<INSCRIPTION_ID>/inscriptions/<PAGE>`: details of the set of 100 child inscriptions on `<PAGE>`.
- `/r/inscription/<INSCRIPTION_ID>`: information about an inscription
- `/r/metadata/<INSCRIPTION_ID>`: JSON string containing the hex-encoded CBOR metadata.
- `/r/parents/<INSCRIPTION_ID>`: the first 100 parent inscription ids.
Expand Down Expand Up @@ -136,6 +138,44 @@ percentile in sats/vB.
}
```

- `/r/children/60bcf821240064a9c55225c4f01711b0ebbcab39aa3fafeefe4299ab158536fai0/inscriptions/49`:

```json
{
"children": [
{
"charms": [
"cursed"
],
"fee": 44,
"height": 813929,
"id": "7cd66b8e3a63dcd2fada917119830286bca0637267709d6df1ca78d98a1b4487i4900",
"number": -223695,
"output": "dcaaeacf58faea0927468ea5a93f33b7d7447841e66f75db5a655d735510c518:0",
"sat": 1897135510683785,
"satpoint": "dcaaeacf58faea0927468ea5a93f33b7d7447841e66f75db5a655d735510c518:0:74188588",
"timestamp": 1698326262
},
...
{
"charms": [
"cursed"
],
"fee": 44,
"height": 813929,
"id": "7cd66b8e3a63dcd2fada917119830286bca0637267709d6df1ca78d98a1b4487i4936",
"number": -223731,
"output": "dcaaeacf58faea0927468ea5a93f33b7d7447841e66f75db5a655d735510c518:0",
"sat": 1897135510683821,
"satpoint": "dcaaeacf58faea0927468ea5a93f33b7d7447841e66f75db5a655d735510c518:0:74188624",
"timestamp": 1698326262
}
],
"more": false,
"page": 49
}
```

- `/r/inscription/3bd72a7ef68776c9429961e43043ff65efa7fb2d8bb407386a9e3b19f149bc36i0`

```json
Expand Down
20 changes: 20 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ pub struct Children {
pub page: usize,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ChildInscriptions {
pub children: Vec<ChildInscriptionRecursive>,
pub more: bool,
pub page: usize,
}

#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct Inscription {
pub address: Option<String>,
Expand Down Expand Up @@ -119,6 +126,19 @@ pub struct InscriptionRecursive {
pub value: Option<u64>,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ChildInscriptionRecursive {
pub charms: Vec<Charm>,
pub fee: u64,
pub height: u32,
pub id: InscriptionId,
pub number: i32,
pub output: OutPoint,
pub sat: Option<ordinals::Sat>,
pub satpoint: SatPoint,
pub timestamp: i64,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Inscriptions {
pub ids: Vec<InscriptionId>,
Expand Down
164 changes: 164 additions & 0 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ impl Server {
"/r/children/:inscription_id/:page",
get(Self::children_recursive_paginated),
)
.route(
"/r/children/:inscription_id/inscriptions",
get(Self::child_inscriptions_recursive),
)
.route(
"/r/children/:inscription_id/inscriptions/:page",
get(Self::child_inscriptions_recursive_paginated),
)
.route("/r/metadata/:inscription_id", get(Self::metadata))
.route("/r/parents/:inscription_id", get(Self::parents_recursive))
.route(
Expand Down Expand Up @@ -1788,6 +1796,65 @@ impl Server {
})
}

async fn child_inscriptions_recursive(
Extension(index): Extension<Arc<Index>>,
Path(inscription_id): Path<InscriptionId>,
) -> ServerResult {
Self::child_inscriptions_recursive_paginated(Extension(index), Path((inscription_id, 0))).await
}

async fn child_inscriptions_recursive_paginated(
Extension(index): Extension<Arc<Index>>,
Path((parent, page)): Path<(InscriptionId, usize)>,
) -> ServerResult {
task::block_in_place(|| {
let parent_sequence_number = index
.get_inscription_entry(parent)?
.ok_or_not_found(|| format!("inscription {parent}"))?
.sequence_number;

let (ids, more) =
index.get_children_by_sequence_number_paginated(parent_sequence_number, 100, page)?;

let children = ids
.into_iter()
.map(|inscription_id| {
let entry = index
.get_inscription_entry(inscription_id)
.unwrap()
.unwrap();

let satpoint = index
.get_inscription_satpoint_by_id(inscription_id)
.ok()
.flatten()
.unwrap();

api::ChildInscriptionRecursive {
charms: Charm::charms(entry.charms),
fee: entry.fee,
height: entry.height,
id: inscription_id,
number: entry.inscription_number,
output: satpoint.outpoint,
sat: entry.sat,
satpoint,
timestamp: timestamp(entry.timestamp.into()).timestamp(),
}
})
.collect();

Ok(
Json(api::ChildInscriptions {
children,
more,
page,
})
.into_response(),
)
})
}

async fn inscriptions(
Extension(server_config): Extension<Arc<ServerConfig>>,
Extension(index): Extension<Arc<Index>>,
Expand Down Expand Up @@ -6256,6 +6323,103 @@ next
assert_eq!(parents_json.page_index, 1);
}

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

let parent_txid = server.core.broadcast_tx(TransactionTemplate {
inputs: &[(1, 0, 0, inscription("text/plain", "hello").to_witness())],
..default()
});

let parent_inscription_id = InscriptionId {
txid: parent_txid,
index: 0,
};

server.assert_response(
format!("/r/children/{parent_inscription_id}/inscriptions"),
StatusCode::NOT_FOUND,
&format!("inscription {parent_inscription_id} not found"),
);

server.mine_blocks(1);

let child_inscriptions_json = server.get_json::<api::ChildInscriptions>(format!(
"/r/children/{parent_inscription_id}/inscriptions"
));
assert_eq!(child_inscriptions_json.children.len(), 0);

let mut builder = script::Builder::new();
for _ in 0..111 {
builder = Inscription {
content_type: Some("text/plain".into()),
body: Some("hello".into()),
parents: vec![parent_inscription_id.value()],
unrecognized_even_field: false,
..default()
}
.append_reveal_script_to_builder(builder);
}

let witness = Witness::from_slice(&[builder.into_bytes(), Vec::new()]);

let txid = server.core.broadcast_tx(TransactionTemplate {
inputs: &[(2, 0, 0, witness), (2, 1, 0, Default::default())],
..default()
});

server.mine_blocks(1);

let first_child_inscription_id = InscriptionId { txid, index: 0 };
let hundredth_child_inscription_id = InscriptionId { txid, index: 99 };
let hundred_first_child_inscription_id = InscriptionId { txid, index: 100 };
let hundred_eleventh_child_inscription_id = InscriptionId { txid, index: 110 };

let child_inscriptions_json = server.get_json::<api::ChildInscriptions>(format!(
"/r/children/{parent_inscription_id}/inscriptions"
));

assert_eq!(child_inscriptions_json.children.len(), 100);

assert_eq!(
child_inscriptions_json.children[0].id,
first_child_inscription_id
);
assert_eq!(child_inscriptions_json.children[0].number, 1); // parent is #0, 1st child is #1

assert_eq!(
child_inscriptions_json.children[99].id,
hundredth_child_inscription_id
);
assert_eq!(child_inscriptions_json.children[99].number, -99); // all but 1st child are cursed

assert!(child_inscriptions_json.more);
assert_eq!(child_inscriptions_json.page, 0);

let child_inscriptions_json = server.get_json::<api::ChildInscriptions>(format!(
"/r/children/{parent_inscription_id}/inscriptions/1"
));

assert_eq!(child_inscriptions_json.children.len(), 11);

assert_eq!(
child_inscriptions_json.children[0].id,
hundred_first_child_inscription_id
);
assert_eq!(child_inscriptions_json.children[0].number, -100);

assert_eq!(
child_inscriptions_json.children[10].id,
hundred_eleventh_child_inscription_id
);
assert_eq!(child_inscriptions_json.children[10].number, -110);

assert!(!child_inscriptions_json.more);
assert_eq!(child_inscriptions_json.page, 1);
}

#[test]
fn inscriptions_in_block_page() {
let server = TestServer::builder()
Expand Down

0 comments on commit 412d37a

Please sign in to comment.