5

Supposedly someone uploaded a Doom clone to the bitcoin blockchain:

https://ordinals.com/content/521f8eccffa4c41a3a7728dd012ea5a4a02feed81f41159231251ecf1e5c79dai0

But I'm a bit confused on exactly what is uploaded using "Ordinals". From a quick read of Ordinals, I'm assuming they are just using OP_RETURN and putting in a encoded string into a block or a transaction?

This encoded string uploaded is a "id" that links to a file on ordinals.com? So technically no real files are uploaded like this Doom clone is it? And if ordinals.com is offline, none of these files are accessible?

And how is this different from colored coins or counterparty from about a decade ago?

3 Answers 3

6

Ordinals Inscriptions don't use OP_RETURN, they are embedded within the script of a taproot input. It's not just a link to a file on some website, the entire file is actually published to the blockchain.

The embedding is done using data pushes inside an unexecuted script branch like so:

OP_0
OP_IF
(embedded data comes here)
OP_ENDIF

You can view the script from your specific example here: https://scriptpath.info/tx/521f8eccffa4c41a3a7728dd012ea5a4a02feed81f41159231251ecf1e5c79da
It consists of 59 pushes of 520 bytes each and one push of 73 bytes.

6
  • So that Doom clone is exactly how big on the blockchain and how much did it cost? Commented Feb 2, 2023 at 16:59
  • 520*59 + 73 = 30,753 bytes. The transaction adds another 445 bytes of overhead for a total of 31,198 bytes (but, because of the witness discount, only 7870 virtual bytes). The fee paid was 19,675 sats. Commented Feb 2, 2023 at 17:45
  • Any reason why they split the data in 520-byte chunks?
    – DeLorean88
    Commented May 9, 2023 at 15:12
  • That's the maximum push size. You can search BIP141 and BIP342 for "520" to learn more. Commented May 9, 2023 at 15:23
  • @Vojtěch Strnad How were you able to pin that that's the script
    – hana
    Commented Jan 16 at 20:28
2

The MIME data type of that inscription is text/html;charset=utf-8. So maybe it is something like Doom in javascript

Ordinals inscriptions do embed the data in transaction data that occupies space in the Bitcoin blockchain.

See also

How to differentiate between BTC transactions and BRC20 transactions on a blockchain?

0

Minimal manual disassembly example

Just to provide a concrete example, let's consider the very first ordinal: https://ordinals.com/inscription/6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799i0

The format is documented at: https://docs.ordinals.com/inscriptions.html with an example:

OP_FALSE
OP_IF
  OP_PUSH "ord"
  OP_PUSH 1
  OP_PUSH "text/plain;charset=utf-8"
  OP_PUSH 0
  OP_PUSH "Hello, world!"
OP_ENDIF

If you run a local node:

bitcoind

we can query the transaction and disassemble it with:

bitcoin-cli getrawtransaction 6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799 true

Among the rest of the disassembly we see:

"txinwitness":
  "152b336f7b6fc69be82df72bb4653eed7e075da88c491c0ad76451fcf0514dd667702aabdeca72cea1427124fc511da6d9ffb43b7e32b908fcef169b19dfc1f6",
  "204a3ca2cf35f7902df1215f823d977df1174048b062e03a44f71c2ee736a60cc5ac0063036f7264010109696d6167652f706e67004d080289504e470d0a1a0a0000000d49484452000000640000006401030000004a2c071700000006504c5445ffffff00000055c2d37e000002ce4944415438cb95d44b6813411807f0944a13105d14b4146916c1b33d150b7d2ce45ab027295a4b0e1e4a5b4a2b4512fac8563c78509abb68051151aacda1600b4db2a1789162021e046d934dc921859addc4906c92dd9dbf21333b01c143e7f6e39bef3133ecbaceb824acb5d109d4da12b22ed2d68808a1bdb50e94b33ccd006c9ee8d624ac5b8ec4b4aa0464deed50559665a78cacc6ba1539c1044df627c18a76a8a5c668090bac4118440719600dc2a8164086a804d5ac544c84984a5aa1aa950895f7260a556861aade5fea5c559d0d304da2528131ce4ea76a958a86793a9a9437eb65d302531db51cca4c32718de86b02e8d8c13a92b7e5728e2a108031093b4d35370ff31ac80faa19d56dee59e20c8b45afdb3bc5a79f59dec373abc6974b2c2f985d18361e27584df92013d7234b32d5e07ec3ab9f3f59a6b3f487b11191483fd5e02659d7fa1a7b549280f52d898854bd22929a8c6ef628e3188bfb6d3f9520226dc8f03209782d4a84c9bd495e197d8d28bf794554c810d37e43c2b39315a683cc6a776ac95176c1368e131653b0d3dcab751e51758d08a64984e72c26c3e8058eb8aa17b80419bfdf01192a11f8b92d035412b07d5781f32a32c9dfd7a1d25b5a8599d4966150190a36744d110109b16c4b960ad12f62aaa58ed371e2f78fd9f78a2d99776aaaf2a0324165a97f52f1694c5141a94e45bf41a13ac5ce624f5a69b4e4aa92ef4ba35fe70bb4437d73a0789c7bb14d155a216e4bc8a7d86b3ed16d83d4242a0965d3ac3b6710b0928fe655c26e8228cd392316550751888e48d1f9fc5244278b59a65b01a2dbe935a69ed4e1446891c1e58ddf781b8e38ba183b34035b8e041940860b0008dfa9787c22dfe90e1ab1dc1157e0657eb8ad398fef6a5bd31edfe5ffc5748fcf6b71cd020d1eebfad0ccfbc8f5a999c7e57ee4f15d6957319add7995cedde664bb5c684e5d73d4a103a4e8c8650266962bf4e67d24c125dae3f8e73f78b6f5177fb5c56a2d73fc4b0000000049454e44ae42608268",
  "c04a3ca2cf35f7902df1215f823d977df1174048b062e03a44f71c2ee736a60cc5"
],

Let's further disassemble the large middle txwitness script which CLI unfortunately does not automatically disassemble for us. As per How to disassemble a bitcoin script? it can be done with:

bitcoin-cli decodescript "204a3ca2cf35f7902df1215f823d977df1174048b062e03a44f71c2ee736a60cc5ac0063036f7264010109696d6167652f706e67004d080289504e470d0a1a0a0000000d49484452000000640000006401030000004a2c071700000006504c5445ffffff00000055c2d37e000002ce4944415438cb95d44b6813411807f0944a13105d14b4146916c1b33d150b7d2ce45ab027295a4b0e1e4a5b4a2b4512fac8563c78509abb68051151aacda1600b4db2a1789162021e046d934dc921859addc4906c92dd9dbf21333b01c143e7f6e39bef3133ecbaceb824acb5d109d4da12b22ed2d68808a1bdb50e94b33ccd006c9ee8d624ac5b8ec4b4aa0464deed50559665a78cacc6ba1539c1044df627c18a76a8a5c668090bac4118440719600dc2a8164086a804d5ac544c84984a5aa1aa950895f7260a556861aade5fea5c559d0d304da2528131ce4ea76a958a86793a9a9437eb65d302531db51cca4c32718de86b02e8d8c13a92b7e5728e2a108031093b4d35370ff31ac80faa19d56dee59e20c8b45afdb3bc5a79f59dec373abc6974b2c2f985d18361e27584df92013d7234b32d5e07ec3ab9f3f59a6b3f487b11191483fd5e02659d7fa1a7b549280f52d898854bd22929a8c6ef628e3188bfb6d3f9520226dc8f03209782d4a84c9bd495e197d8d28bf794554c810d37e43c2b39315a683cc6a776ac95176c1368e131653b0d3dcab751e51758d08a64984e72c26c3e8058eb8aa17b80419bfdf01192a11f8b92d035412b07d5781f32a32c9dfd7a1d25b5a8599d4966150190a36744d110109b16c4b960ad12f62aaa58ed371e2f78fd9f78a2d99776aaaf2a0324165a97f52f1694c5141a94e45bf41a13ac5ce624f5a69b4e4aa92ef4ba35fe70bb4437d73a0789c7bb14d155a216e4bc8a7d86b3ed16d83d4242a0965d3ac3b6710b0928fe655c26e8228cd392316550751888e48d1f9fc5244278b59a65b01a2dbe935a69ed4e1446891c1e58ddf781b8e38ba183b34035b8e041940860b0008dfa9787c22dfe90e1ab1dc1157e0657eb8ad398fef6a5bd31edfe5ffc5748fcf6b71cd020d1eebfad0ccfbc8f5a999c7e57ee4f15d6957319add7995cedde664bb5c684e5d73d4a103a4e8c8650266962bf4e67d24c125dae3f8e73f78b6f5177fb5c56a2d73fc4b0000000049454e44ae42608268"

which gives:

4a3ca2cf35f7902df1215f823d977df1174048b062e03a44f71c2ee736a60cc5
OP_CHECKSIG
0
OP_IF
6582895
1
696d6167652f706e67
0
89504e470d0a1a0a0000000d49484452000000640000006401030000004a2c071700000006504c5445ffffff00000055c2d37e000002ce4944415438cb95d44b6813411807f0944a13105d14b4146916c1b33d150b7d2ce45ab027295a4b0e1e4a5b4a2b4512fac8563c78509abb68051151aacda1600b4db2a1789162021e046d934dc921859addc4906c92dd9dbf21333b01c143e7f6e39bef3133ecbaceb824acb5d109d4da12b22ed2d68808a1bdb50e94b33ccd006c9ee8d624ac5b8ec4b4aa0464deed50559665a78cacc6ba1539c1044df627c18a76a8a5c668090bac4118440719600dc2a8164086a804d5ac544c84984a5aa1aa950895f7260a556861aade5fea5c559d0d304da2528131ce4ea76a958a86793a9a9437eb65d302531db51cca4c32718de86b02e8d8c13a92b7e5728e2a108031093b4d35370ff31ac80faa19d56dee59e20c8b45afdb3bc5a79f59dec373abc6974b2c2f985d18361e27584df92013d7234b32d5e07ec3ab9f3f59a6b3f487b11191483fd5e02659d7fa1a7b549280f52d898854bd22929a8c6ef628e3188bfb6d3f9520226dc8f03209782d4a84c9bd495e197d8d28bf794554c810d37e43c2b39315a683cc6a776ac95176c1368e131653b0d3dcab751e51758d08a64984e72c26c3e8058eb8aa17b80419bfdf01192a11f8b92d035412b07d5781f32a32c9dfd7a1d25b5a8599d4966150190a3674
09b16c4b960ad12f62aaa58ed371e2f78fd9f78a2d99776aaaf2a0324165a97f52f1694c5141a94e45bf41a13ac5ce624f5a69b4e4aa92ef4ba35fe70bb4437d73a0789c7bb14d155a216e4bc8a7d86b3ed16d83d4242a0965d3ac3b6710b0928fe655c26e8228cd392316550751888e48d1f9fc5244278b59a65b01a2dbe935a69ed4e1446891c1e58ddf781b8e38ba183b34035b8e041940860b0008dfa9787c22dfe90e1ab1dc1157e0657eb8ad398fef6a5bd31edfe5ffc5748fcf6b71cd020d1eebfad0ccfbc8f5a999c7e57ee4f15d6957319add7995cedde664bb5c684e5d73d4a103a4e8c8650266962bf4e67d24c125dae3f8e73f78b6f5177fb5c56a2d73fc4b0000000049454e44ae426082
OP_ENDIF

Disassembly

With the help of https://stackoverflow.com/questions/7826526/transform-hexadecimal-information-to-binary-using-a-linux-command we can convert the hex dumps to binary with xxd -r -p:

  1. 6582895
    

    is a decimal number, in hex:

    printf "%x\n" 6582895
    

    it is:

    64726f
    

    and:

    printf 64726f | xxd -r -p
    

    gives dro, which is the inverse of ord, for ordinals. All of this is just a disassembly artifact, we can see that the actual data contains 6f7264 in the usual ord order.

  2. 1 is the content_type tag according to https://docs.ordinals.com/inscriptions.html So this specifies the filetype of the data that follows.

    printf 696d6167652f706e67 | xxd -r -p
    

    gives:

    image/png
    

    which is the filetype.

    It is worth noting that the filetype used to be mandatory for an inscription to be considered valid and get a valid number, but this restriction was later dropped leading to the creation of corresponding negative cursed ordinals such as: https://ordinals.com/inscription/4b9a822a057743813efbefa0dd21d0a01342ee793ce2ce5bd499a5f262187553i0

  3. 0 specifies that the actual content is coming up. We can decode it with:

    printf '
    89504e470d0a1a0a0000000d49484452000000640000006401030000004a2c071700000006504c5445ffffff00000055c2d37e000002ce4944415438cb95d44b6813411807f0944a13105d14b4146916c1b33d150b7d2ce45ab027295a4b0e1e4a5b4a2b4512fac8563c78509abb68051151aacda1600b4db2a1789162021e046d934dc921859addc4906c92dd9dbf21333b01c143e7f6e39bef3133ecbaceb824acb5d109d4da12b22ed2d68808a1bdb50e94b33ccd006c9ee8d624ac5b8ec4b4aa0464deed50559665a78cacc6ba1539c1044df627c18a76a8a5c668090bac4118440719600dc2a8164086a804d5ac544c84984a5aa1aa950895f7260a556861aade5fea5c559d0d304da2528131ce4ea76a958a86793a9a9437eb65d302531db51cca4c32718de86b02e8d8c13a92b7e5728e2a108031093b4d35370ff31ac80faa19d56dee59e20c8b45afdb3bc5a79f59dec373abc6974b2c2f985d18361e27584df92013d7234b32d5e07ec3ab9f3f59a6b3f487b11191483fd5e02659d7fa1a7b549280f52d898854bd22929a8c6ef628e3188bfb6d3f9520226dc8f03209782d4a84c9bd495e197d8d28bf794554c810d37e43c2b39315a683cc6a776ac95176c1368e131653b0d3dcab751e51758d08a64984e72c26c3e8058eb8aa17b80419bfdf01192a11f8b92d035412b07d5781f32a32c9dfd7a1d25b5a8599d4966150190a3674
    09b16c4b960ad12f62aaa58ed371e2f78fd9f78a2d99776aaaf2a0324165a97f52f1694c5141a94e45bf41a13ac5ce624f5a69b4e4aa92ef4ba35fe70bb4437d73a0789c7bb14d155a216e4bc8a7d86b3ed16d83d4242a0965d3ac3b6710b0928fe655c26e8228cd392316550751888e48d1f9fc5244278b59a65b01a2dbe935a69ed4e1446891c1e58ddf781b8e38ba183b34035b8e041940860b0008dfa9787c22dfe90e1ab1dc1157e0657eb8ad398fef6a5bd31edfe5ffc5748fcf6b71cd020d1eebfad0ccfbc8f5a999c7e57ee4f15d6957319add7995cedde664bb5c684e5d73d4a103a4e8c8650266962bf4e67d24c125dae3f8e73f78b6f5177fb5c56a2d73fc4b0000000049454e44ae426082
    ' | xxd -r -p > tmp.png
    

    which gives our image:

    tmp.png

    enter image description here

Payloads are generally not contiguous in the block data due to PUSHDATA opcodes

One important fact about ordinals is that unlike with OP_RETURN, the payload is not necessarily encoded contiguously.

In our example, we see that two separate constants were pushed to the stack.

This is not very explicit in the disassembly, but each one has an OP_PUSHDATA2 opcode immediately before it, which is encoded as byte 0x4d can handle only up to 520 bytes at a time:

Therefore, you can't just directly carve out the payloads from the blockchain data, block parsing is required.

In our example, the raw data contained:

4d 0802 [ 89504e47 ... 190a3674 ] 4d 1101 [ 09b16c4b ... ae426082 ]

so there would have been a trash data of 4d1101 if we had tried to carve out values directly without parsing.

There can be multiple ordinals per transaction

Any valid:

OP_FALSE
OP_IF
  OP_PUSH "ord"

in txinwitness indicates the start of a new ordinal, and you can have multiple of those per transaction.

This is why there is that i0 at the end of the URLs at ordinals.com such as: https://ordinals.com/inscription/6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799i0

The i0 means "inscription 0" and serves to disambiguate between multiple different ordinals in the same transaction.

i0, i1, etc. are just taken in blockchain serialization order.

Tested on Ubuntu 24.04.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.