Jhonatan Pinheiro
Loading page...
Jhonatan Pinheiro
Loading page...
Jhonatan Pinheiro
Loading page...
How blockchain actually works, what real-world asset tokenization delivers (and what it doesn't), and how Bitcoin got NFTs and fungible tokens with Ordinals and Runes.
There is a lot of content about blockchain that is either investment hype or an impenetrable academic paper. This one tries to be the third thing: technical documentation for people who write code and want to understand what these technologies actually do, where they solve a real problem and where they are the wrong tool.
Three subjects, in order of abstraction:
This is not investment advice. It is technical documentation. Nothing here suggests buying, selling or holding any asset — and the final section is precisely about the risks.
A blockchain is an append-only, replicated, ownerless database, in which the order of the records is agreed on by participants who do not trust each other.
Technically, three pieces:
# The chain of hashes, in practice (Bitcoin Core)
bitcoin-cli getblockhash 840000
bitcoin-cli getblock 0000000000000000000320283a032748cef8227873ff4872689bf23f1cda83a5 1
# the "previousblockhash" field links this block to the previous oneThe Merkle tree is what allows you to prove a transaction is in a block without downloading the whole block — the basis of any light client:
bitcoin-cli gettxoutproof '["<txid>"]' # proof of inclusion
bitcoin-cli verifytxoutproof "<proof>" # verificationWhat makes a blockchain different from a replicated database: in a database, the administrator is in charge. On a public blockchain, nobody is — the rule is the code every node runs, and changing that rule requires convincing the entire network.
Miners compete to find a nonce that makes the block's hash fall below a target. Finding it is expensive (energy), verifying it is instantaneous. The valid chain is the one that has accumulated the most work.
bitcoin-cli getblockchaininfo | jq '{blocks, difficulty, chainwork}'
bitcoin-cli getmininginfo | jq '{networkhashps, difficulty}'The energy spend is not a side effect: it is the mechanism itself. Rewriting history requires redoing the work of every subsequent block, faster than the entire network. The cost is the security.
Validators deposit capital as collateral. Anyone validating an invalid block loses part of the deposit (slashing). The cost stops being energy and becomes locked-up capital.
| Proof of Work | Proof of Stake | |
|---|---|---|
| Cost of an attack | Hardware + energy | Capital at stake |
| Energy | High by design | Low |
| Finality | Probabilistic (confirmations) | Deterministic (in epochs) |
| Entry for new validators | Buy hardware | Buy and lock up the asset |
| Main criticism | Energy consumption | A tendency towards capital concentration |
Finality is the concept that most confuses people coming from databases: on Bitcoin, a transaction is never 100% irreversible — it only becomes exponentially unlikely to be reversed with each block. That is why exchanges wait for confirmations.
It solves well:
It does not solve:
The question that separates a serious project from technological theatre: is there more than one party, without mutual trust, that needs to agree on the same state? If the answer is no, a Postgres with an audit log solves it better, cheaper and faster.
# Lightning: a payment channel off-chain, settled on the L1
lncli openchannel --node_key=<pubkey> --local_amt=1000000
lncli listchannels | jq '.channels[] | {remote_pubkey, capacity, local_balance}'
lncli closechannel --funding_txid=<txid> --output_index=0The rule of thumb: the further you get from the L1, the cheaper and faster it is — and the more extra trust you have to assume.
// ERC-20: the essentials of the fungible interface
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address conta) external view returns (uint256);
function transfer(address para, uint256 valor) external returns (bool);
function approve(address gastador, uint256 valor) external returns (bool);
function transferFrom(address de, address para, uint256 valor) external returns (bool);
}For RWAs there is a third family, that of permissioned tokens, in which a transfer only happens if both parties are cleared:
// ERC-3643 (T-REX): a transfer subject to identity verification
function transfer(address para, uint256 valor) public override returns (bool) {
require(identityRegistry.isVerified(para), "destinatario nao verificado");
require(compliance.canTransfer(msg.sender, para, valor), "regra de compliance");
return super.transfer(para, valor);
}That is the central difference between "free" crypto and a regulated asset: the token of a financial asset needs to know who is on the other side.
An RWA (Real World Asset) is the on-chain representation of an asset that exists outside it: a government bond, a fund share, a receivable, a property, private credit, a commodity.
Here is what most promotional texts leave out:
| Category | What gets tokenized | Why it works |
|---|---|---|
| Government bonds | US Treasuries, national treasury | A standardised, liquid asset with low credit risk |
| Funds | Money market fund shares | Cheaper settlement and distribution |
| Private credit | Receivables, loans | Fractionalisation and access for smaller investors |
| Real estate | A fraction of a property or of an SPV | A smaller ticket; liquidity is still the challenge |
| Commodities | Gold, energy, carbon credits | Traceability of origin |
The cases that worked share a clear pattern: they work better the more standardised, liquid and regulated the original asset is. Tokenized government bonds thrived; fractional real estate is still hard — not because of a technical limitation, but because the problem was never technological.
From the point of view of whoever builds it, a serious project always has these layers:
[ Asset in the real world ] property, bond, receivable
│
[ Legal structure ] SPV, fund, assignment contract — who is legally answerable
│
[ Custody ] who holds the asset and answers for it
│
[ Oracle / attestation ] price, proof of reserve, asset status
│
[ Token ] permissioned contract (ERC-3643, ERC-1400)
│
[ Compliance ] KYC/AML, allowlist, limits per jurisdiction
│
[ Distribution ] platform, wallet, secondary marketThe code is the smallest part of the problem. A permissioned token contract is a few hundred lines; the legal structure and the custody take months.
Without this, the token is an unverifiable promise:
// Query a proof-of-reserve feed before allowing issuance
interface AggregatorV3Interface {
function latestRoundData() external view returns (
uint80 roundId, int256 answer, uint256 startedAt,
uint256 updatedAt, uint80 answeredInRound
);
}
function emitir(uint256 quantidade) external onlyEmissor {
(, int256 reserva, , uint256 atualizadoEm, ) = feedReserva.latestRoundData();
require(block.timestamp - atualizadoEm < 1 days, "dado de reserva desatualizado");
require(totalSupply() + quantidade <= uint256(reserva), "emissao acima do lastro");
_mint(msg.sender, quantidade);
}Note the require on the age: a stale oracle is as dangerous as a wrong one, and forgetting that check is one of the most common findings in an audit.
The last question is decisive: nearly every regulated RWA token does have a freeze function — the law requires it. That is not a flaw, it is a requirement. But you need to know it exists, and who holds the key.
To understand Ordinals and Runes you have to understand three things about Bitcoin.
Bitcoin does not have accounts with balances. It has UTXOs (Unspent Transaction Outputs): pieces of coin, each with a value and a spending condition. A transaction consumes whole UTXOs and creates new ones.
bitcoin-cli listunspent
# [{ "txid": "...", "vout": 0, "amount": 0.015, "scriptPubKey": "..." }]
# Each UTXO is spent whole; the change comes back as a new UTXO
bitcoin-cli gettxout "<txid>" 0That is exactly what makes it possible to track individual satoshis: since each UTXO has an identifiable origin, you can follow the trail of any fraction.
Each output carries a script defining the spending condition. It is deliberately not Turing-complete: no loops, no global state, no contract calls.
# OP_RETURN: a deliberately unspendable output, used to record data
bitcoin-cli createrawtransaction \
'[{"txid":"<txid>","vout":0}]' \
'[{"data":"48656c6c6f"}]'Two upgrades prepared the ground, without that being the aim:
Put the two together: it became viable to put a file inside a Bitcoin transaction, paying a discounted fee. Nobody designed this with images in mind — it was an emergent consequence. That distinction sits at the heart of all the controversy that followed.
Ordinals is a protocol created by Casey Rodarmor and launched in January 2023. It has two independent parts, and confusing them is the most common mistake.
Each satoshi gets a serial number, assigned by the order in which it was mined, and is tracked across transactions by the first-in-first-out rule: the first satoshis in are the first satoshis out.
# Numbering and locating a specific satoshi
ord list <outpoint> # which sats are in this UTXO
ord find 1234567890 # which UTXO holds sat number N
ord traits 1234567890 # rarity: uncommon, rare, epic, legendaryNote this: it is a convention, not consensus. The Bitcoin network has no idea what an ordinal is. The indexer running that rule over the chain is what knows. Two indexers with different implementations would reach different results — the rule only holds because everyone agrees to use the same one.
An inscription attaches content (an image, text, HTML, audio) to a specific satoshi, writing the bytes into the witness of a Taproot transaction, inside an envelope that Bitcoin ignores:
OP_FALSE
OP_IF
OP_PUSH "ord" # protocol marker
OP_PUSH 1 # field: content-type
OP_PUSH "image/png"
OP_PUSH 0 # field: body
OP_PUSH <file bytes>
OP_ENDIFThe OP_FALSE OP_IF means the whole block is never executed — as far as consensus is concerned, it is inert data. To the indexer, it is the inscription.
The process takes two transactions, and understanding this avoids an expensive mistake:
# 1) COMMIT: creates a Taproot output committed to the inscription's script
# 2) REVEAL: spends that output revealing the script — this is where the data enters the chain
ord wallet inscribe --fee-rate 15 --file arte.png
# returns: commit txid, reveal txid and the inscription id (<txid>i<index>)
ord wallet inscriptions
ord wallet send --fee-rate 12 <address> <inscription-id>An inscription lives on a satoshi. If your wallet treats that satoshi as ordinary change, it can spend it paying a network fee — and your inscription vanishes into a miner.
# Protect the inscription's UTXO from being spent by accident
bitcoin-cli lockunspent false '[{"txid":"<txid>","vout":0}]'
bitcoin-cli listlockunspent
# Never use an ordinary wallet for inscriptions: use one that understands sat control
ord wallet balance # separates cardinal (spendable) from ordinal (protected)Use a wallet with Ordinals support and keep the funds separate. An ordinary wallet has no idea what an inscribed sat is.
Inscriptions compete for block space with financial transactions. At peak moments this raised fees noticeably and filled the mempool — which generated (and still generates) a legitimate discussion in the community about the "appropriate" use of block space.
bitcoin-cli getmempoolinfo | jq '{size, bytes, mempoolminfee}'
bitcoin-cli estimatesmartfee 6Before Runes, the way to create a fungible token on Bitcoin was BRC-20: inscriptions with a JSON saying "deployed", "minted", "transferred". It works, but with two serious problems: each operation is an inscription (junk in the witness) and the balance depends entirely on an external indexer interpreting text.
Runes, also from Casey Rodarmor, launched at block 840,000 — the April 2024 halving — to solve this natively within the UTXO model.
The protocol writes a runestone into an OP_RETURN output (data in the body of the transaction, not in the witness), and the balances live in the UTXOs themselves.
OP_RETURN
OP_13 # the Runes protocol marker
<payload> # encoded fields: etching, mint, edicts, pointerThree operations make up the whole life cycle:
# Etching: creating a rune with open issuance terms
ord wallet batch --fee-rate 20 --batch etching.yaml
# etching.yaml
# mode: separate-outputs
# etching:
# rune: MINHA•PRIMEIRA•RUNE
# divisibility: 2
# premine: 1000
# symbol: ¤
# supply: 21000
# terms:
# amount: 100
# cap: 200
ord wallet mint --fee-rate 15 --rune MINHA•PRIMEIRA•RUNE
ord wallet send --fee-rate 15 <address> 500:MINHA•PRIMEIRA•RUNE
ord wallet balance # shows sats and runes per UTXO•) that is not part of the identity. Short names were reserved on purpose: they only become available over time, to prevent everything being taken in the first blocks.amount), how many mints exist (cap) and in which window of blocks they are allowed.| BRC-20 | Runes | |
|---|---|---|
| Where it writes | An inscription in the witness | OP_RETURN in the body |
| Balance model | Off-chain state per indexer | Native UTXO |
| Junk on the chain | High (3 inscriptions per cycle) | Low (one OP_RETURN) |
| Transfer | Inscribe and transfer | An edict in the transaction itself |
| Indexer complexity | High (JSON parsing) | Lower (a defined binary format) |
Both, however, share the same fundamental trait: Bitcoin's consensus validates neither of them. A Bitcoin node sees only ordinary transactions. All the token semantics live in the indexers.
| Protocol | Where it lives | Does consensus validate it? | Privacy | Profile |
|---|---|---|---|---|
| Ordinals | Witness (L1) | No | Public | Unique assets, art, digital artefacts |
| BRC-20 | Inscriptions (L1) | No | Public | Fungible token — legacy today |
| Runes | OP_RETURN (L1) | No | Public | Efficient fungible token |
| RGB | Off-chain, anchored to the L1 | No | High (data off-chain) | Assets with privacy and contracts |
| Liquid | Federated sidechain | Yes, on the sidechain | Confidential | Institutional issuance, regulated assets |
| Taproot Assets | Off-chain + Lightning | No | Medium | Stablecoins with instant settlement |
For RWAs on Bitcoin, the serious candidates are Liquid and Taproot Assets — not Runes. A regulated asset needs controlled issuance, confidentiality and the ability to freeze, and none of that exists in a protocol based on a public OP_RETURN.
Honest documentation includes the counter-argument.
On Ordinals and Runes:
On RWAs:
The harshest criticism, and the most useful: the overwhelming majority of projects that call themselves blockchain do not need blockchain. If there is a central company that issues, custodies, resolves disputes and can reverse an operation, you have built an expensive, slow database with better marketing. That does not invalidate the technology — it invalidates the wrong use of it.
The path that teaches the most, in order:
# 1. Run a node. This is where it clicks: you start verifying instead of believing.
bitcoind -daemon -txindex=1
bitcoin-cli getblockchaininfo
# 2. Work on testnet/signet — play money, mistakes at no cost
bitcoind -signet -daemon
bitcoin-cli -signet getnewaddress
# 3. Stand up an Ordinals/Runes indexer and watch the chain
ord --signet server --http-port 8080
# 4. Inscribe and create a rune on signet before doing anything on mainnet
ord --signet wallet inscribe --fee-rate 1 --file teste.txtFor the contracts and RWA side:
# A local EVM environment, spending nothing
npm install --save-dev hardhat
npx hardhat node # local chain
npx hardhat test # contract tests
# Standards worth studying before writing from scratch:
# ERC-20, ERC-721 (base) · ERC-3643 and ERC-1400 (regulated assets)
# OpenZeppelin (audited implementations) · Chainlink (oracles and proof of reserve)And the three rules that prevent losses while you learn:
Blockchain is a tool with an extremely high cost — in performance, in energy or in capital — that buys one specific property: verifiable agreement between parties without mutual trust. When you need that, there is no substitute. When you do not, any database is better in every respect.
RWAs are the most honest test of that proposition, because they expose exactly where the technology ends and the law begins. Ordinals and Runes are the most interesting demonstration of another phenomenon: how a deliberately limited network ended up used in a way nobody foresaw, out of features created for another purpose.
Understanding both cases teaches more about distributed systems than any white paper — including about when not to use them.