Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delegator content /r/undelegated-content/<INSCRIPTION_ID> #3932

Merged
merged 14 commits into from
Oct 26, 2024
12 changes: 12 additions & 0 deletions docs/src/inscriptions/recursion.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The recursive endpoints are:
- `/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/delegator/<INSCRIPTION_ID>`: inscription content of the delegator.
raphjaph marked this conversation as resolved.
Show resolved Hide resolved
- `/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 All @@ -63,6 +64,17 @@ plain-text responses.
- `/blockhash/<HEIGHT>`: block hash at given block height.
- `/blocktime`: UNIX time stamp of latest block.

Delegated inscriptions:

An inscription with delegated content "foo" and original content "bar" will return the following:

| Endpoint | Response |
|--------------------|----------|
| `/content/:id` | foo |
| `/r/delegator/:id` | bar |

This allows delegated inscriptions to access both the content they delegate to and their own original content.

Examples
--------

Expand Down
103 changes: 103 additions & 0 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ impl Server {
"/r/children/:inscription_id/inscriptions/:page",
get(Self::child_inscriptions_recursive_paginated),
)
.route("/r/delegator/:inscription_id", get(Self::content_delegator))
.route("/r/metadata/:inscription_id", get(Self::metadata))
.route("/r/parents/:inscription_id", get(Self::parents_recursive))
.route(
Expand Down Expand Up @@ -1493,6 +1494,36 @@ impl Server {
})
}

async fn content_delegator(
Extension(index): Extension<Arc<Index>>,
Extension(settings): Extension<Arc<Settings>>,
Extension(server_config): Extension<Arc<ServerConfig>>,
Path(inscription_id): Path<InscriptionId>,
accept_encoding: AcceptEncoding,
) -> ServerResult {
task::block_in_place(|| {
if settings.is_hidden(inscription_id) {
return Ok(PreviewUnknownHtml.into_response());
}

let inscription = index
.get_inscription_by_id(inscription_id)?
.ok_or_not_found(|| format!("inscription {inscription_id}"))?;

if inscription.delegate().is_some() {
elocremarc marked this conversation as resolved.
Show resolved Hide resolved
Ok(
Self::content_response(inscription, accept_encoding, &server_config)?
.ok_or_not_found(|| format!("inscription {inscription_id} content"))?
.into_response(),
)
} else {
Err(ServerError::NotFound(
"inscription is not delegated".to_string(),
))
}
})
}

fn content_response(
inscription: Inscription,
accept_encoding: AcceptEncoding,
Expand Down Expand Up @@ -6610,6 +6641,78 @@ next
);
}

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

server.mine_blocks(1);

let delegate = Inscription {
content_type: Some("text/plain".into()),
body: Some("foo".into()),
..default()
};

let delegate_txid = server.core.broadcast_tx(TransactionTemplate {
inputs: &[(1, 0, 0, delegate.to_witness())],
..default()
});

let delegate_id = InscriptionId {
txid: delegate_txid,
index: 0,
};

server.mine_blocks(1);

let inscription = Inscription {
content_type: Some("text/plain".into()),
body: Some("bar".into()),
delegate: Some(delegate_id.value()),
..default()
};

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

server.mine_blocks(1);

let id = InscriptionId { txid, index: 0 };

server.assert_response(format!("/r/delegator/{id}"), StatusCode::OK, "bar");

server.assert_response(format!("/content/{id}"), StatusCode::OK, "foo");

// Test normal inscription without delegate
let normal_inscription = Inscription {
content_type: Some("text/plain".into()),
body: Some("baz".into()),
..default()
};

let normal_txid = server.core.broadcast_tx(TransactionTemplate {
inputs: &[(3, 0, 0, normal_inscription.to_witness())],
..default()
});

server.mine_blocks(1);

let normal_id = InscriptionId {
txid: normal_txid,
index: 0,
};

server.assert_response(
format!("/r/delegator/{normal_id}"),
StatusCode::NOT_FOUND,
"inscription is not delegated",
);

server.assert_response(format!("/content/{normal_id}"), StatusCode::OK, "baz");
}

#[test]
fn content_proxy() {
let server = TestServer::builder().chain(Chain::Regtest).build();
Expand Down
Loading