Jhonatan Pinheiro
Loading page...
Jhonatan Pinheiro
Loading page...
Jhonatan Pinheiro
Loading page...
Ordinal theory, the inscription envelope field by field, commit and reveal, the runestone byte by byte, etching commitments, edicts, cenotaphs and the costly mistakes.
O Bitcoin não tem contrato inteligente. Não tem estado global, não tem laço, não tem armazenamento persistente por conta. Ainda assim, desde 2023 ele carrega imagens, textos, coleções e tokens fungíveis.
Isso não aconteceu por uma mudança de consenso. Aconteceu porque dois recursos criados para outra finalidade — o desconto de peso do SegWit e o script path do Taproot — abriram, sem querer, espaço barato para dados arbitrários. Ordinals e Runes são o que se construiu em cima disso.
Este guia é a documentação que eu queria ter encontrado: o formato dos bytes, as regras exatas, os comandos e os erros que custam dinheiro.
Três conceitos precisam estar firmes, senão o resto não faz sentido.
O Bitcoin não guarda saldo por endereço. Ele guarda saídas não gastas — cada uma com um valor em satoshis e uma condição de gasto. Uma transação consome saídas inteiras e cria novas.
bitcoin-cli listunspent
# [{ "txid": "abc...", "vout": 0, "amount": 0.00015000, "confirmations": 12 }]
bitcoin-cli gettxout "abc..." 0Como cada saída tem origem rastreável, é possível seguir frações específicas de moeda através da história. É disso que a teoria ordinal se aproveita.
O SegWit (2017) separou a assinatura do corpo da transação e criou a unidade de peso (weight unit, WU):
O tamanho virtual (vsize), que é o que define a taxa, é o peso dividido por 4. Na prática: dado no witness custa um quarto.
bitcoin-cli decoderawtransaction "<hex>" | jq '{size, vsize, weight}'
# size: tamanho total em bytes
# weight: 4 * (bytes do corpo) + 1 * (bytes do witness)
# vsize: weight / 4 <- é isto que multiplica a taxa em sats/vBO Taproot (2021) permite gastar uma saída revelando um script guardado em uma árvore. Esse script vai no witness — e não tem limite prático de tamanho imposto pelo consenso.
Junte as duas coisas: um script Taproot pode carregar um arquivo inteiro, pagando um quarto da taxa. Nenhuma das duas atualizações foi proposta com esse objetivo. A consequência foi emergente — e é a raiz de toda a discussão que veio depois.
A teoria ordinal, criada por Casey Rodarmor, é uma convenção de numeração. Ela não altera o Bitcoin em nada: é uma regra que qualquer pessoa pode aplicar sobre a cadeia e chegar ao mesmo resultado.
Regra 1 — atribuição. Satoshis são numerados de 0 a 2.099.999.997.690.000, na ordem em que são minerados. Os satoshis do subsídio de um bloco recebem os próximos números disponíveis.
Regra 2 — transferência. Satoshis passam pelas transações em ordem primeiro a entrar, primeiro a sair (FIFO). Concatene as entradas na ordem em que aparecem; distribua para as saídas na ordem em que aparecem.
# Entradas: [ A: sats 100-199 ] [ B: sats 500-549 ]
# Saídas: [ X: 120 sats ] [ Y: 30 sats ]
# X recebe: 100-199 (100 sats) + 500-519 (20 sats)
# Y recebe: 520-549 (30 sats)Regra 3 — taxas. Os satoshis pagos como taxa vão para o minerador e entram na saída da coinbase, logo depois dos satoshis do subsídio. É por isso que gastar um sat inscrito como taxa entrega sua inscrição ao minerador.
Vale insistir: nada disso é validado pela rede. Um nó Bitcoin não sabe o que é um ordinal. Quem sabe é o indexador que roda essa regra. Duas implementações divergentes produziriam saldos divergentes — a convenção só vale porque todos usam a mesma.
O mesmo satoshi pode ser escrito de cinco formas. Todas identificam o mesmo número.
| Notação | Exemplo | O que expressa |
|---|---|---|
| Inteiro | 2099994106992659 | O número de série puro |
| Decimal | 3891094.16797 | bloco.offset — bloco de origem e posição dentro dele |
| Grau | 1°111094′214″16797‴ | Ciclo, época, período de dificuldade e posição |
| Percentil | 99.99971949060254% | Posição relativa no supply total |
| Nome | satoshi | Codificação em base 26 (letras a–z) |
A notação de grau é a que revela a raridade, porque expõe os quatro ciclos do Bitcoin de uma vez:
A°B′C″D‴
# A = ciclo (a cada 6 halvings, quando halving e ajuste coincidem)
# B = índice do bloco na época de halving (0 a 209.999)
# C = índice do bloco no período de dificuldade (0 a 2.015)
# D = índice do satoshi dentro do blocoDaí sai a escala de raridade:
| Raridade | Condição | Quantidade aproximada |
|---|---|---|
| Common | Qualquer sat que não seja o primeiro do bloco | ~2,1 quatrilhões |
| Uncommon | Primeiro sat de cada bloco | ~6,9 milhões |
| Rare | Primeiro sat de cada ajuste de dificuldade | ~3.400 |
| Epic | Primeiro sat de cada época de halving | 32 |
| Legendary | Primeiro sat de cada ciclo | 5 |
| Mythic | Primeiro sat do bloco gênesis | 1 |
ord find 2099994106992659 # em que UTXO está este sat
ord list <outpoint> # que sats estão neste UTXO
ord traits 2099994106992659 # raridade, ciclo, época, notaçõesA raridade é uma propriedade da convenção, não do protocolo. Um sat "rare" é indistinguível de qualquer outro para o consenso do Bitcoin — vale o que o mercado que aceita a convenção decidir que vale.
Uma inscrição anexa conteúdo a um satoshi. O conteúdo vai dentro de um envelope no script Taproot revelado no gasto:
OP_FALSE
OP_IF
OP_PUSH "ord" # marcador do protocolo
OP_PUSH 0x01 # tag 1 = content-type
OP_PUSH "image/png"
OP_PUSH 0x00 # tag 0 = corpo (body)
OP_PUSH <bytes ...> # conteúdo, em pedaços de até 520 bytes
OP_PUSH <bytes ...>
OP_ENDIFTrês detalhes que explicam por que isso funciona:
OP_FALSE OP_IF ... OP_ENDIF cria um bloco que nunca executa. Para o consenso, é dado inerte — não custa validação, não quebra nada.A inscrição é atribuída ao primeiro satoshi da primeira saída da transação de reveal — a menos que um ponteiro diga outra coisa (tag 2, adiante).
O identificador de uma inscrição é o txid do reveal seguido do índice:
6fb976ab49dcec017f1e201e84395983204ae1a7c2abf7ced0a85d692e442799i0
# <txid do reveal> + "i" + <índice da inscrição naquela transação>Depois do marcador "ord", o envelope carrega pares de tag e valor. As tags são números:
| Tag | Campo | Para que serve |
|---|---|---|
| 0 | body | O conteúdo em si (sempre por último) |
| 1 | content-type | Tipo MIME: image/png, text/plain;charset=utf-8, text/html |
| 2 | pointer | Em que sat da transação a inscrição deve cair |
| 3 | parent | Id da inscrição-pai (procedência) |
| 5 | metadata | Metadados em CBOR |
| 7 | metaprotocol | Nome de um protocolo que roda por cima (ex.: BRC-20) |
| 9 | content-encoding | Codificação do corpo, como gzip |
| 11 | delegate | Id de outra inscrição que fornece o conteúdo |
A convenção de paridade importa: tags pares são essenciais — um indexador que não reconhece uma delas deve tratar a inscrição como inválida; tags ímpares podem ser ignoradas com segurança por versões antigas. É o mecanismo que permite evoluir o protocolo sem quebrar quem não atualizou.
# Conteúdo comprimido, para caber mais barato
OP_PUSH 0x09 OP_PUSH "gzip"
OP_PUSH 0x01 OP_PUSH "text/html;charset=utf-8"
OP_PUSH 0x00 OP_PUSH <html comprimido>Inscrever exige duas transações. Entender isso evita a maior parte dos erros operacionais.
# 1) COMMIT
# Cria uma saída Taproot cujo endereço compromete a árvore de scripts,
# e um dos ramos dessa árvore é o envelope com o seu conteúdo.
# Nesta etapa NADA do conteúdo aparece na cadeia.
# 2) REVEAL
# Gasta aquela saída pelo script path, revelando o ramo do envelope.
# É aqui que os bytes entram na blockchain, no witness.Consequências práticas:
ord wallet inscribe --fee-rate 15 --file arte.png
# {
# "commit": "e2f1...",
# "reveal": "6fb9...",
# "inscriptions": [{ "id": "6fb9...i0", "location": "6fb9...:0:0" }],
# "total_fees": 24310
# }Limite de relay. Por padrão, um nó só repassa transações com até 400.000 unidades de peso (-maxstandardtxweight). Passando disso, a transação é válida mas não circula pela rede: só entra em bloco se for entregue direto a um minerador.
Limite de bloco. 4.000.000 WU. Uma única inscrição pode, em tese, ocupar quase um bloco inteiro.
A conta da taxa. Como witness custa 1 WU por byte:
# Estimativa para um arquivo de 100 KB no witness
# 100.000 bytes * 1 WU = 100.000 WU
# vsize = 100.000 / 4 = 25.000 vB
# a 20 sats/vB -> 25.000 * 20 = 500.000 sats de taxa (só o reveal)
bitcoin-cli estimatesmartfee 6 | jq '.feerate' # BTC/kvB
bitcoin-cli getmempoolinfo | jq '{size, bytes, mempoolminfee}'Regra de bolso: o mesmo arquivo no corpo da transação custaria quatro vezes mais. É o desconto do witness que torna a prática economicamente viável — e é exatamente por isso que parte da comunidade considera o desconto um erro de projeto.
Reduzir custo, na prática:
# 1. Comprima antes (tag 9 = content-encoding)
gzip -9 -c pagina.html > pagina.html.gz
# 2. Prefira formatos enxutos: SVG e HTML costumam ganhar de PNG
# 3. Use recursão: referencie bibliotecas já inscritas em vez de reinscrevê-las
# 4. Inscreva em lote: uma transação para várias inscrições
ord wallet batch --fee-rate 8 --batch lote.yamlA tag 3 aponta para uma inscrição-pai. Para que a filiação seja válida, a inscrição-pai precisa ser gasta na transação de reveal — ou seja, só quem controla o pai consegue criar um filho. É assim que uma coleção prova autenticidade sem registro central.
# lote.yaml — coleção com procedência
mode: separate-outputs
parent: 6fb9...i0
inscriptions:
- file: 001.png
- file: 002.png
- file: 003.pngA tag 11 faz uma inscrição apontar para o conteúdo de outra. Mil itens que compartilham a mesma imagem podem ser mil inscrições minúsculas delegando a uma só — o custo despenca.
Uma inscrição pode buscar outra através do endpoint /content/<id>. Isso permite inscrever uma biblioteca uma vez e reutilizá-la:
<script src="/content/6fb9...i0"></script>
<img src="/content/a1b2...i0">Outros endpoints de recursão expõem dados da própria cadeia, o que permite arte generativa que reage ao estado do Bitcoin:
/r/blockheight # altura atual
/r/blockhash # hash do bloco
/r/blocktime # timestamp
/r/sat/<numero> # inscrições naquele sat
/r/children/<id> # filhos de uma inscriçãoA tag 5 carrega metadados em CBOR — binário, mais compacto que JSON:
# {"nome": "Peça 001", "autor": "Jhonatan", "edicao": 1}
# vira alguns bytes de CBOR no envelope
ord wallet inscribe --fee-rate 10 --file arte.png --json-metadata meta.jsonUm satoshi pode receber mais de uma inscrição. As posteriores são reconhecidas, mas ficam claramente marcadas como reinscrições — a primeira é a canônica.
Nos primeiros meses, algumas inscrições foram criadas de formas que a implementação de referência não previa: envelopes duplicados na mesma entrada, tags desconhecidas, estruturas fora do padrão.
Em vez de descartá-las, o ord passou a numerá-las com números negativos — as cursed inscriptions. Era um sinal de "isto existe, mas não é canônico".
No bloco 824.544, o chamado jubileu encerrou essa distinção: a partir dali, as formas antes amaldiçoadas passaram a receber numeração positiva normal. As antigas mantiveram seus números negativos como registro histórico.
ord list <outpoint> | jq '.inscriptions'
# número negativo = inscrição anterior ao jubileu, criada de forma não canônicaA lição de engenharia aqui é boa: em protocolo baseado em convenção, mudar a regra é decisão social, não técnica. Não houve fork — houve acordo entre quem roda o indexador.
# Pré-requisito: nó completo com índice de transações
bitcoind -daemon -txindex=1
bitcoin-cli getblockchaininfo | jq '{blocks, initialblockdownload}'
# Indexador (a primeira indexação demora horas e ocupa dezenas de GB)
ord --index-sats server --http-port 8080
# Carteira
ord wallet create # gera e mostra a seed — guarde offline
ord wallet receive # endereço para depositar
ord wallet balance # separa cardinal (gastável) de ordinal
ord wallet outputs # todos os UTXOs
ord wallet inscriptions # o que você tem inscrito# Inscrever
ord wallet inscribe --fee-rate 12 --file arte.png
ord wallet inscribe --fee-rate 12 --file arte.png --destination bc1p...
ord wallet inscribe --fee-rate 12 --file arte.png --postage 10000sat
# Enviar
ord wallet send --fee-rate 10 bc1p... 6fb9...i0 # por id da inscrição
ord wallet send --fee-rate 10 bc1p... 2099994106992659 # por número de sat
# Consultar
ord wallet transactions
ord decode --txid <txid> # mostra o envelope decodificadoO parâmetro --postage merece atenção: é quantos satoshis acompanham a inscrição na saída. O padrão é 10.000 sats. Valores muito baixos podem cair abaixo do limite de poeira e travar transferências futuras.
Antes das Runes, criar token fungível no Bitcoin significava usar BRC-20: inscrições com um JSON dizendo o que se queria fazer.
{"p":"brc-20","op":"deploy","tick":"ordi","max":"21000000","lim":"1000"}
{"p":"brc-20","op":"mint","tick":"ordi","amt":"1000"}
{"p":"brc-20","op":"transfer","tick":"ordi","amt":"100"}Funciona, mas com três defeitos sérios:
Runes, lançado por Casey Rodarmor no bloco 840.000 (o halving de abril de 2024), foi desenhado para resolver isso sendo nativo ao modelo UTXO: o saldo mora no próprio UTXO, e a instrução vai em uma única saída OP_RETURN.
Um runestone é uma saída OP_RETURN assim:
OP_RETURN
OP_13 # marcador do protocolo Runes (OP_PUSHNUM_13)
<push de dados> # payload
<push de dados> # (se houver mais de um, concatene na ordem)O payload é uma sequência de inteiros LEB128 (varint de tamanho variável), lidos como pares tag → valor:
| Tag | Nome | Função |
|---|---|---|
| 0 | Body | A partir daqui vêm os edicts |
| 1 | Divisibility | Casas decimais (0 a 38) |
| 2 | Flags | Bits que ligam etching, terms e turbo |
| 3 | Spacers | Onde entram os separadores visuais do nome |
| 4 | Rune | O nome, codificado em base 26 |
| 5 | Symbol | Um caractere Unicode |
| 6 | Premine | Quantidade reservada ao criador |
| 8 | Cap | Número máximo de mints |
| 10 | Amount | Quantidade entregue por mint |
| 12 / 14 | HeightStart / HeightEnd | Janela de mint por altura absoluta |
| 16 / 18 | OffsetStart / OffsetEnd | Janela de mint relativa ao etching |
| 20 | Mint | Id da rune que está sendo cunhada |
| 22 | Pointer | Saída que recebe o saldo não alocado |
A mesma regra de paridade das inscrições vale aqui: tag par desconhecida invalida o runestone (vira cenotaph); tag ímpar desconhecida é ignorada. É o que permite adicionar recursos no futuro sem quebrar indexadores antigos.
# Decodificar um runestone da cadeia
ord decode --txid <txid>
bitcoin-cli getrawtransaction <txid> 1 | jq '.vout[] | select(.scriptPubKey.type=="nulldata")'Por que OP_RETURN e não witness? Porque OP_RETURN é provadamente não gastável — os nós podem descartar essas saídas do conjunto de UTXOs, sem inchar a memória da rede. Custa mais caro por byte (fica no corpo, sem desconto), e é justamente por isso que o formato é binário e enxuto.
Etching é o ato de criar a rune. Define nome, símbolo, divisibilidade, premine e as regras de cunhagem.
# etching.yaml
mode: separate-outputs
etching:
rune: MINHA•PRIMEIRA•RUNE
divisibility: 2
premine: 1000
symbol: ¤
supply: 21000
terms:
amount: 100
cap: 200
height: [840000, 900000] # janela absoluta (opcional)
turbo: true
inscriptions:
- file: logo.png # opcional: um "cenotaph visual" da runeord wallet batch --fee-rate 20 --batch etching.yamlAqui está o detalhe que mais confunde quem etcha pela primeira vez: o nome da rune precisa ser comprometido antes, e o compromisso precisa ter pelo menos 6 confirmações antes da transação de etching.
O motivo é anti-front-running: sem isso, qualquer um veria seu nome no mempool e publicaria a mesma rune com taxa maior. Com o commitment, quem tenta copiar precisaria esperar seis blocos — tempo suficiente para o original confirmar.
# Na prática, o ord faz isso por você e espera:
# "Waiting for rune commitment ... to mature (6 confirmations)"
# São ~1 hora entre iniciar e a rune existir. Não interrompa o processo.premine + (amount × cap).# premine 1000 + (100 * 200) = 21.000 unidades
# Quanto maior a fatia do premine, mais centralizada é a distribuição.Premine é o primeiro número que qualquer pessoa deveria olhar antes de tocar em uma rune. Premine de 90% significa que o criador detém quase tudo.
O campo Flags (tag 2) é um conjunto de bits:
| Bit | Nome | Significado |
|---|---|---|
| 0 | Etching | Esta transação cria uma rune |
| 1 | Terms | O etching define regras de mint aberto |
| 2 | Turbo | A rune adere automaticamente a futuras mudanças do protocolo |
Nomes de rune usam apenas letras maiúsculas de A a Z, codificadas como um inteiro em base 26 modificada.
MINHA•PRIMEIRA•RUNE
# A identidade real é MINHAPRIMEIRARUNE.
# Os "•" são spacers (tag 3): decoração visual, não fazem parte do nome.
# Não existem duas runes com o mesmo nome, ainda que com spacers diferentes.Se todos os nomes estivessem disponíveis no lançamento, os curtos teriam sido tomados nos primeiros blocos. O protocolo evita isso liberando os nomes ao longo do tempo:
# Comprimento mínimo pela altura atual, na prática:
# 840.000 -> 13 letras
# 857.500 -> 12 letras
# 875.000 -> 11 letras
# ...
# 1.050.000 -> 1 letraRunes etchadas antes do bloco 840.000 não existem: a primeira rune possível é a do próprio bloco de lançamento.
Cada rune é identificada pelo bloco e pela posição da transação dentro dele:
840000:1 # bloco 840.000, transação 1
# É este id que os edicts usam — não o nome.Se o etching definiu terms, qualquer pessoa pode cunhar até o cap ser atingido, dentro da janela permitida.
ord wallet mint --fee-rate 15 --rune MINHA•PRIMEIRA•RUNE
# Um mint é um runestone com a tag Mint (20) apontando o rune id:
# OP_RETURN OP_13 <20> <bloco> <tx>Regras que valem conhecer:
amount. Não existe mint parcial.height ou offset) não é erro de transação: ele simplesmente não produz nada, e a taxa foi paga do mesmo jeito.cap, mints deixam de produzir. Em runes populares isso vira corrida por bloco, e é o que costuma explodir a taxa da rede em janelas de mint.height) usa números absolutos de bloco; janela por offset (offset) conta a partir do bloco do etching.Transferência é um edict dentro do runestone: uma tripla (id, quantidade, saída).
ord wallet send --fee-rate 12 bc1p... 500:MINHA•PRIMEIRA•RUNEDuas convenções fazem toda a diferença:
OP_RETURN". É o mecanismo de airdrop em uma transação só.# Transação com 3 saídas (índices 0, 1, 2) mais o OP_RETURN:
# edict (840000:1, 0, 3) -> divide todo o saldo entre as saídas 0, 1 e 2O que sobra sem edict explícito vai para a primeira saída não-OP_RETURN. A tag Pointer (22) muda esse destino:
# Sem pointer: o troco de runes cai na saída 0
# Com pointer = 2: o troco cai na saída 2Esquecer disso é uma das formas mais fáceis de mandar saldo para o endereço errado — inclusive para o do destinatário, quando você queria só o troco.
Um cenotaph é um runestone malformado. O nome não é acidente: cenotáfio é um túmulo vazio.
Um runestone vira cenotaph quando:
E a consequência é dura, deliberadamente:
| Situação | O que acontece |
|---|---|
| Runes entrando na transação | São queimadas |
| O runestone continha um etching | A rune é criada com supply zero e não pode ser cunhada |
| O runestone continha um mint | O mint conta contra o cap, mas as unidades são queimadas |
Por que tão severo? Porque a alternativa — ignorar o erro e seguir — abriria espaço para divergência entre indexadores. Queimar é determinístico e igual para todos. O custo dessa escolha é que um bug na sua implementação destrói saldo real, sem recurso.
# Antes de assinar qualquer transação de runes construída à mão:
ord decode --txid <txid> # o ord aponta cenotaph
# Em caso de dúvida, teste em signet primeiro. Sempre.Como nem Ordinals nem Runes são validados pelo consenso, todo saldo depende de um indexador. Rodar o seu é a única forma de não confiar em terceiros.
# Requisitos aproximados do ord com índice de sats
# - nó Bitcoin completo com -txindex=1 (~700 GB e crescendo)
# - dezenas de GB adicionais para o índice do ord
# - SSD é praticamente obrigatório; a indexação inicial leva horas
ord --index-sats --index-runes server --http-port 8080
curl -s localhost:8080/status | jqEndpoints úteis da API local:
curl -s localhost:8080/inscription/<id> -H "Accept: application/json"
curl -s localhost:8080/output/<txid>:<vout> -H "Accept: application/json"
curl -s localhost:8080/rune/MINHA•PRIMEIRA•RUNE -H "Accept: application/json"
curl -s localhost:8080/sat/2099994106992659 -H "Accept: application/json"Existem APIs de terceiros que poupam o trabalho de indexar. Elas são convenientes e legítimas, mas note o que você está aceitando: a resposta delas é a fonte de verdade da sua aplicação. Para exibir, tudo bem; para decidir sobre custódia de valor, rode o seu índice.
O risco aqui raramente é criptográfico — é operacional.
# 1. Separe as carteiras. Sats inscritos e runes NUNCA na carteira do dia a dia.
ord wallet balance # cardinal = gastável | ordinal = protegido
# 2. Trave os UTXOs que carregam valor
bitcoin-cli lockunspent false '[{"txid":"<txid>","vout":0}]'
bitcoin-cli listlockunspent
# 3. Confira o destino antes de enviar
ord wallet send --dry-run --fee-rate 10 bc1p... 6fb9...i0Regras que evitam quase todo prejuízo:
bitcoind -signet -daemon
ord --signet --index-sats server
ord --signet wallet inscribe --fee-rate 1 --file teste.txtOrdinals e Runes são, tecnicamente, um caso de estudo notável: dois protocolos completos construídos sem alterar uma linha do consenso, aproveitando recursos que existiam para outra finalidade.
Isso traz uma característica que precisa estar clara antes de qualquer coisa: o Bitcoin não conhece nenhum dos dois. Não existe validação de saldo, não existe mensagem de erro amigável, não existe reversão. Existe uma convenção que vale enquanto os indexadores concordarem — e um conjunto de regras implacáveis quando você erra a codificação.
Para quem programa, o valor de estudar isso vai além do assunto: é um exemplo raro de protocolo bem documentado, com decisões de projeto explícitas (por que OP_RETURN e não witness, por que queimar em vez de ignorar, por que paridade de tags) e consequências verificáveis na cadeia. Dá para ler o código, reproduzir cada byte em signet e conferir.
E, se for tocar em mainnet: signet primeiro, carteira separada sempre, e nada de valor sem hardware wallet.