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

Recursive Endpoints #2175

Merged
merged 9 commits into from
Jun 15, 2023
Merged

Recursive Endpoints #2175

merged 9 commits into from
Jun 15, 2023

Conversation

raphjaph
Copy link
Collaborator

At the moment (not deployed to ordinals.com yet) you can reference the content of other inscriptions through the /content/:inscription_id but it would also be really cool to reference bitcoin internal metrics. So I propose the following as well:

/blockhash: current block hash
/blockheight: current block height
/blocktime: current block time as UTC timestamp

Of course there are a bunch of others we could add, so I'm open to suggestions. Also it should be possible to get the block hash at a specific height through/blockhash/:height. Analogous for the other endpoints.

@casey We have a /block-count endpoint. Should I change it to /blockcount to match the others?

@raphjaph raphjaph changed the title recursive endpoints Recursive Endpoints Jun 12, 2023
@raphjaph raphjaph requested review from casey and veryordinally June 12, 2023 10:48
@casey
Copy link
Collaborator

casey commented Jun 12, 2023

Deplaning in Lisbon at the moment, so I can't give this a proper review, but the additional endpoints need to be combined into one CSP headers, instead of adding new ones. CSP headers are checked one at a time, and all must pass. So it should be:

      HeaderValue::from_static("default-src *:*/content *:*/blockheight *:*/blockcount *:*/blockhash 'unsafe-eval' 'unsafe-inline' data:"),

What's the difference between block height and block count? I'd only have one, if the only difference is one starts at zero and the other at one.

@raphjaph
Copy link
Collaborator Author

the additional endpoints need to be combined into one CSP headers, instead of adding new ones. CSP headers are checked one at a time, and all must pass. So it should be:

      HeaderValue::from_static("default-src *:*/content *:*/blockheight *:*/blockcount *:*/blockhash 'unsafe-eval' 'unsafe-inline' data:"),

Ah ok, gotcha. Will change later because I'm heading out now.

What's the difference between block height and block count? I'd only have one, if the only difference is one starts at zero and the other at one.

Yes, that's basically the difference. We use /block-count quite extensively in the integration tests but will try to convert to /blockheight since that's what most people know of/recognize.

@FishbrainAxolotl
Copy link

I vote use Block Height, like the .bitmap standard.

@FishbrainAxolotl
Copy link

Personally I prefer "/404.bitmap:" or "/404.bmp:" or even "/h:" (for height) rather than "/blockheight:404" Every bit matters right?

Maybe there can be a "shortcuts" update to squash the bits across the board.

The whole point of http://bitmap.land is to find the most efficient solution for spatial bitcoin meta and save as many bits and bytes where we can so that's my input as a contributor to that project.

@kevinfaveri
Copy link

kevinfaveri commented Jun 13, 2023

Hey, can we also make available inside inscriptions the inscription number and id? I think those are cool as well to be used as seeds for generative art algos (maybe arguably possible by getting for example from the URL? But better to have this as an API)

@casey
Copy link
Collaborator

casey commented Jun 13, 2023

Hey, can we also make available inside inscriptions the inscription number and id? I think those are cool as well to be used as seeds for generative art algos (maybe arguably possible by getting for example from the URL? But better to have this as an API)

I don't se a benefit for providing an API to retrieve the inscription ID, since it can already be fetched from the URL via JavaScript. Inscription numbers are somewhat problematic, given that cursed inscription numbers are permanently unstable, and bugs in the indexer could make even existing inscription numbers unstable, so I don't think they should be exposed via an API.

@kevinfaveri
Copy link

If we exclude inscription number of the equation, my suggestion makes even less sense since you can use the id from the URL of the iframe, yes. Okay with it.

@zmeyer44
Copy link
Contributor

zmeyer44 commented Jun 13, 2023

What about an endpoint that references a taproot address and return an array of inscription Ids that the address holds?
Perhaps /address-inscriptions/[address] since just /address/[address] it a bit to general and it would be somewhat unintuitive for /address to just return an array of inscriptionIds.

@JussCubs
Copy link

Can we expose the sat number, name, birthdate, and data about the sat the inscription is on? Perhaps expose output first mapping to the sats in the output and then being able to reference data about the sats inside of the output.

Also if we can get more data from ordinals index exposed such as sat info, date it's inscribed, etc, can we have the inscription reference itself and its own data? As of the time of inscribing we don't know the inscriptionID of the inscription at hand. Not sure how this will work but absolutely would love to reference future non-existing inscriptionIDs too somehow (need to think this one through)

@kevinfaveri
Copy link

kevinfaveri commented Jun 13, 2023

Can we expose the sat number, name, birthdate, and data about the sat the inscription is on? Perhaps expose output first mapping to the sats in the output and then being able to reference data about the sats inside of the output.

Also if we can get more data from ordinals index exposed such as sat info, date it's inscribed, etc, can we have the inscription reference itself and its own data? As of the time of inscribing we don't know the inscriptionID of the inscription at hand. Not sure how this will work but absolutely would love to reference future non-existing inscriptionIDs too somehow (need to think this one through)

For inscription id, you can get using JS from the URL already. But agree that having sats info is also cool for gen art

@raphjaph
Copy link
Collaborator Author

What about an endpoint that references a taproot address and return an array of inscription Ids that the address holds? Perhaps /address-inscriptions/[address] since just /address/[address] it a bit to general and it would be somewhat unintuitive for /address to just return an array of inscriptionIds.

We do not index addresses at the moment so can't add this endpoint easily. We will probably add some more endpoints in the future and if we have a table for addresses by then we could add that.

@raphjaph
Copy link
Collaborator Author

Can we expose the sat number, name, birthdate, and data about the sat the inscription is on? Perhaps expose output first mapping to the sats in the output and then being able to reference data about the sats inside of the output.
Also if we can get more data from ordinals index exposed such as sat info, date it's inscribed, etc, can we have the inscription reference itself and its own data? As of the time of inscribing we don't know the inscriptionID of the inscription at hand. Not sure how this will work but absolutely would love to reference future non-existing inscriptionIDs too somehow (need to think this one through)

For inscription id, you can get using JS from the URL already. But agree that having sats info is also cool for gen art

Agreed, sats info would be quite nice.

src/subcommand/server.rs Outdated Show resolved Hide resolved
src/subcommand/server.rs Outdated Show resolved Hide resolved
src/subcommand/server.rs Outdated Show resolved Hide resolved
src/subcommand/server.rs Outdated Show resolved Hide resolved
src/subcommand/server.rs Outdated Show resolved Hide resolved
src/subcommand/server.rs Outdated Show resolved Hide resolved
Copy link
Collaborator Author

@raphjaph raphjaph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls fix

@Xen0ph0n
Copy link

Hi Team, outside of the issues with application layer presentation and security domains for browsers like safari, in contemplation of this upgrade I think there may be a more fundamental concern with regards to scalability:

Currently ordinals are self contained entities, roughly equating to a single session to transfer from either ordinals.com or a canonical mirror like magic eden.

While other proprietary display sites (ord.io / unisat / ordessy etc) already allow for insecure arbitrary external includes (libs or data exposing viewers to security risks which Recursion aims to minimize) those calls are often being made minimally and assuredly orders of magnitude fewer than once canonically allowed.

After delivery of recursion, the simple loading of a PFP or other composite ordinal will hit the hardcoded and allowed recursion locations at a rate multiple orders of magnitude higher than currently.

Example a 10K pfp made up of 10 traits each, all of which being pulled from ordinals.com data at each load (10x sessions)

Example a generative art design utilizing p5.js pulling from ordinals.com at each load (multiple megs) and possibly other large libraries to create the composition, all of which would necessarily come from the limited bandwidth ordinals site vs properly equipped CDN's used to serve such packages to the global internet audience.

It seems this compos-ability, re-introduces very formative web2 issues with scale and performances that may not have been accounted for when considering static or self-contained digitial artifacts as they exist canonically today.

Are there plans to fund and amplify infrastructure to account for this to avoid DDoS of the allowed paths? I believe a small increase in implementation of this standard could elsewise DDoS the front end APIs and ordinal content delivery sites.

Thanks for your consideration! Happy to chat more on discord / twitter or github if helpful! We'd love to see this implemented successfully, a first step might be allowing only limited size strings or content to be composed. ?

@Dawidbtc
Copy link

@Xen0ph0n that's a good point.

For example one of the recent uses of recursion I saw was a visualizer for a Ordinals NFT collection (100 supply) which would make 100 requests to /content/

@tansanDOTeth
Copy link

tansanDOTeth commented Jun 14, 2023

Hi Team, outside of the issues with application layer presentation and security domains for browsers like safari, in contemplation of this upgrade I think there may be a more fundamental concern with regards to scalability:

Currently ordinals are self contained entities, roughly equating to a single session to transfer from either ordinals.com or a canonical mirror like magic eden.

While other proprietary display sites (ord.io / unisat / ordessy etc) already allow for insecure arbitrary external includes (libs or data exposing viewers to security risks which Recursion aims to minimize) those calls are often being made minimally and assuredly orders of magnitude fewer than once canonically allowed.

After delivery of recursion, the simple loading of a PFP or other composite ordinal will hit the hardcoded and allowed recursion locations at a rate multiple orders of magnitude higher than currently.

Example a 10K pfp made up of 10 traits each, all of which being pulled from ordinals.com data at each load (10x sessions)

Example a generative art design utilizing p5.js pulling from ordinals.com at each load (multiple megs) and possibly other large libraries to create the composition, all of which would necessarily come from the limited bandwidth ordinals site vs properly equipped CDN's used to serve such packages to the global internet audience.

It seems this compos-ability, re-introduces very formative web2 issues with scale and performances that may not have been accounted for when considering static or self-contained digitial artifacts as they exist canonically today.

Are there plans to fund and amplify infrastructure to account for this to avoid DDoS of the allowed paths? I believe a small increase in implementation of this standard could elsewise DDoS the front end APIs and ordinal content delivery sites.

Thanks for your consideration! Happy to chat more on discord / twitter or github if helpful! We'd love to see this implemented successfully, a first step might be allowing only limited size strings or content to be composed. ?

This is a great point. Most of the data (if not all) is static content. It can all be cached into a CDN and scale wouldn't be much of an issue especially if the team is using something like CloudFront or Cloudflare. However, I have no idea how they architected their tech infra.

@raphjaph
Copy link
Collaborator Author

Yes, the /content/<INSCRIPTION_ID> endpoint is static content which allows aggressive per machine caching with the Cache-Control header via max-age and immutable directives. Additionally, on a global view, we have Cloudflare in front of everything which is also tuned to cache many endpoints. /blockhash, /blockheight, etc. cannot be cached but they don't represent a crazy load since they are relatively short strings.

With recursive inscriptions we are basically serving small websites that request a bunch of static resources. From a load/DoS perspective nothing has changed since those endpoints could've been hit before as well.

Please let me know if I have wrong assumptions in my reasoning here, appreciate all feedback!

@tansanDOTeth
Copy link

tansanDOTeth commented Jun 15, 2023

Now that I understand this better, I think the current namespace is too generic. It's very likely that /content/ path will lead to a collision; the path is likely already used in other websites. It would be more ideal to have a more descriptive namespace such as /inscriptions/<INSCRIPTION_ID> . This would be particular helpful for other websites especially if Ordinals expects other websites to support recursive inscriptions.

Even more ideal would be to add /ordinals/ before everything:

/ordinals/inscriptions/:inscription_id
/ordinals/blockhash: current block hash
/ordinals/blockheight: current block height
/ordinals/blocktime: current block time as UTC timestamp

This way, if I had an existing infrastructure, I could just target all paths with /ordinals/ to redirect to a CDN for just ordinals related static content to which would also be useful for recursive items.

@raphjaph
Copy link
Collaborator Author

I don't think collision will be a problem since the full path would have the form /content/521f8eccffa4c41a3a7728dd012ea5a4a02feed81f41159231251ecf1e5c79dai0 and I doubt that some other resources lie there. For CDN purposes your router could match anything that matches the inscription ID pattern and you could also play around with CORS headers to fine tune.

Additionally, we already use the /content/ endpoint to serve inscription content and reusing it makes caching easier.

The endpoints/paths should be as short as possible to save bytes but at the same time should be decipherable by humans. This way navigation and viewing of the explorer behaves similar to building recursive inscriptions. The building blocks for recursive inscriptions should be discoverable, if that makes sense.

@raphjaph raphjaph merged commit fffbef4 into ordinals:master Jun 15, 2023
@@ -749,7 +792,7 @@ impl Server {
);
headers.append(
header::CONTENT_SECURITY_POLICY,
HeaderValue::from_static("default-src *:*/content/ 'unsafe-eval' 'unsafe-inline' data:"),
HeaderValue::from_static("default-src *:*/content/ *:*/blockheight *:*/blockhash *:*/blockhash/ *:*/blocktime 'unsafe-eval' 'unsafe-inline' data:"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are there two blockhash entries here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, why is the blockcount endpoint not permitted? Though I guess it can be inferred from blockheight + 1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm regarding first question, I see that one ends in a slash and not the other

@sondotpin
Copy link
Contributor

@raphjaph do you have a plan to add more recursive endpoints:
/sat/:inscription_id: return sat number of an inscription
/sat/:sat_id: return all inscriptions in a sat number

@sondotpin
Copy link
Contributor

Screen Shot 2023-08-26 at 15 23 23

This is probably a problem in demand in practice: upgradeable:

  • �Ordinal 1 is child, using content of Ordinal 2
  • But when Ordinal 2 has re-inscribed => Ordinal 1 also update depends on latest inscription on Ordinal 2

@raphjaph @casey How do you think?

@zmeyer44
Copy link
Contributor

For the sat recursive endpoint, I think it makes sense to have seperate endpoints for the sat details and the inscriptions associated with a sat. Perhaps /sat/[satNumber] just returns information about the sat like timestamp, rarity, decimal, etc. Then something like /sat/[satNumber]/inscriptions would return an array of all the inscription Ids for inscriptions linked to that sat number. It would also be cool to be able to select a particular inscription by adding the index to the end of the url /sat/[satNumber]/inscriptions/[inscriptionIndex] i.e. the first inscription on the sat in index 0, and to get the most recent inscription you could use the index -1.

@sondotpin
Copy link
Contributor

#2200

@raphjaph @casey @zmeyer44
Danny Huep has talk about this

@raphjaph raphjaph deleted the recursive-endpoints branch January 31, 2024 18:52
popcnt1 pushed a commit to popcnt1/ord that referenced this pull request Jan 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.