This article breaks down the technical process of minting an Ordinals inscription by examining the underlying code. We'll explore the key concepts and step-by-step construction of the required Bitcoin transactions.
Key Concepts: OutPoint and SatPoint
Bitcoin transactions operate on a UTXO (Unspent Transaction Output) model. Each transaction output has a unique identifier called an OutPoint, which can be referenced as an input in future transactions.
An OutPoint consists of two fields:
TxHash: A 32-byte hash representing the previous transaction.Index: A 4-byte integer indicating the specific output index from that transaction.
The Ordinals protocol uniquely identifies and numbers each satoshi (the smallest Bitcoin unit). Since satoshis exist within UTXOs, a SatPoint is used to define their precise location.
A SatPoint structure contains:
- An
OutPoint(as defined above) - An
offset(the specific position within that output)
This combination allows any single satoshi to be uniquely located.
The Two-Phase Commit/Reveal Process
Ordinals inscriptions are created using a two-phase process involving two transactions: a Commit transaction and a Reveal transaction.
- Commit Transaction: This creates a new Taproot output that commits to a script containing the inscription content.
- Reveal Transaction: This spends the output created by the commit transaction, thereby revealing the inscribed content on the blockchain.
This approach is necessary because spending from a Taproot script can only be done from an existing Taproot output. The actual inscription data is stored within the witness data of the reveal transaction's input.
Step-by-Step Code Walkthrough
Let's examine the key steps in the create_inscription_transactions function, which orchestrates this process.
Step 1: Prepare Inscription Content and UTXOs
The process begins by loading the inscription content from a file and fetching the available unspent transaction outputs (UTXOs) from the wallet.
let inscription = Inscription::from_file(options.chain(), &self.file)?;
let mut utxos = index.get_unspent_outputs(Wallet::load(&options)?)?;Step 2: Obtain a SatPoint
The code checks if a specific SatPoint was provided. If not, it selects an available UTXO that doesn't already contain an inscription.
let satpoint = if let Some(satpoint) = satpoint {
satpoint
} else {
// Logic to find a UTXO without existing inscriptions
utxos.keys().find(|outpoint| ... ).map(...)...
};Step 3: Check for Existing Inscriptions
The selected OutPoint is verified to ensure it hasn't been used for a previous inscription, preventing duplicate minting on the same satoshi.
Step 4: Generate a Key Pair
A new Secp256k1 key pair is generated, which will be used to construct the reveal transaction and for signing purposes.
let secp256k1 = Secp256k1::new();
let key_pair = UntweakedKeyPair::new(&secp256k1, &mut rand::thread_rng());Step 5: Build the Reveal Script
This is where the inscription content is embedded into the script. The builder follows the standard Ordinals protocol format.
let builder = script::Builder::new()
.push_slice(&public_key.serialize())
.push_opcode(opcodes::all::OP_CHECKSIG)
.push_opcode(opcodes::OP_FALSE)
.push_opcode(opcodes::all::OP_IF)
.push_slice(PROTOCOL_ID) // b"ord"
// Additional content type and body pushing logic
.push_opcode(opcodes::all::OP_ENDIF);The resulting script matches the structure defined in the Ordinals documentation:
OP_FALSE
OP_IF
OP_PUSH "ord"
OP_1
OP_PUSH "text/plain;charset=utf-8"
OP_0
OP_PUSH "Hello, world!"
OP_ENDIFStep 6: Construct Taproot Spend Script
The reveal script is added as a leaf to a Taproot tree, and the necessary control block is computed for later use in the reveal transaction.
let taproot_spend_info = TaprootBuilder::new()
.add_leaf(0, reveal_script.clone())
.finalize(&secp256k1, public_key);Step 7: Generate Tweaked Key
The Taproot output public key is derived by tweaking the original public key with the Merkle root of the script tree. This enhances privacy and flexibility.
let commit_tx_address = Address::p2tr_tweaked(taproot_spend_info.output_key(), network);Step 8: Calculate Reveal Transaction Fee
An initial fee calculation is performed for the reveal transaction, though actual construction happens later.
Step 9: Build Commit Transaction
The commit transaction is constructed, which creates the Taproot output that will be spent by the reveal transaction.
let unsigned_commit_tx = TransactionBuilder::build_transaction_with_value(
satpoint,
inscriptions,
utxos,
commit_tx_address.clone(),
change,
commit_fee_rate,
reveal_fee + TARGET_POSTAGE,
)?;Step 10: Construct Reveal Transaction
Using the output created by the commit transaction, the reveal transaction is built. This transaction will actually publish the inscription content to the blockchain.
let (mut reveal_tx, fee) = Self::build_reveal_transaction(
&control_block,
reveal_fee_rate,
OutPoint {
txid: unsigned_commit_tx.txid(),
vout: vout.try_into().unwrap(),
},
TxOut {
script_pubkey: destination.script_pubkey(),
value: output.value,
},
&reveal_script,
);Step 11: Value Validation Check
The code verifies that the commit transaction provides sufficient value to cover fees and avoids creating dust outputs.
Step 12: Compute Signature Hash
The signature hash is computed for the reveal transaction, which will be signed to authorize the spending of the commit transaction output.
Step 13: Push Signature to Witness Data
The signature, reveal script, and control block are added to the witness data of the reveal transaction, completing its construction.
witness.push(signature.as_ref());
witness.push(reveal_script);
witness.push(&control_block.serialize());Step 14: Sign and Broadcast Transactions
Finally, the commit transaction is signed using the wallet, and both transactions are broadcast to the Bitcoin network.
let signed_raw_commit_tx = client.sign_raw_transaction_with_wallet(...)?;
let commit = client.send_raw_transaction(&signed_raw_commit_tx)?;
let reveal = client.send_raw_transaction(&reveal_tx)?;👉 Explore advanced inscription strategies
Technical Considerations and Best Practices
The Ordinals inscription process involves several complex technical considerations:
Fee Management: Both commit and reveal transactions require adequate fee allocation. The reveal transaction fee must account for the data size of the inscription content.
UTXO Selection: Choosing the right UTXO is crucial. It must have sufficient value to cover both transaction fees and avoid containing existing inscriptions.
Script Size Limitations: Inscription content is limited by Bitcoin's script size constraints. Content is typically chunked into 520-byte segments within the script.
Network Compatibility: The process requires compatibility with Taproot-enabled Bitcoin networks and nodes.
Frequently Asked Questions
What is the difference between commit and reveal transactions?
The commit transaction creates a Taproot output that commits to containing inscription data, while the reveal transaction actually spends that output and publishes the data to the blockchain. This two-phase approach is necessary for Taproot script spending.
How are inscription fees calculated?
Fees depend on several factors: network congestion, inscription size, and chosen fee rates. The reveal transaction fee is typically higher as it includes the inscription data weight. Both transactions require separate fee calculations.
Can any UTXO be used for inscriptions?
Not exactly. The UTXO must not already contain inscriptions and should have sufficient value to cover the required fees. The code specifically checks for "cardinal UTXOs" (those without existing ordinal content).
What happens if the reveal transaction fails?
If only the commit transaction confirms but the reveal transaction fails, the inscribed satoshi remains locked in the Taproot output without revealing its content. This represents a failed inscription attempt where the fees are lost.
How does Taproot enhance Ordinals inscriptions?
Taproot provides greater privacy and flexibility compared to previous script methods. It allows inscriptions to appear as regular single-signature transactions to external observers while actually containing complex script data.
What are the size limitations for inscriptions?
While Bitcoin's block size limit imposes practical constraints, the protocol itself can handle inscriptions of several megabytes. However, larger inscriptions require higher fees and may face network acceptance issues.
Conclusion
The Ordinals inscription process demonstrates a sophisticated application of Bitcoin's Taproot upgrade. By using a two-phase commit/reveal approach with specialized script construction, it enables arbitrary data storage directly on the Bitcoin blockchain.
This technical implementation showcases how Bitcoin's flexible scripting capabilities can be repurposed for innovative applications beyond simple value transfer. The process carefully balances data storage needs with Bitcoin's security and consensus requirements.
👉 View real-time inscription tools
Understanding this process provides deeper insight into both Ordinals protocol mechanics and advanced Bitcoin transaction construction. As the ecosystem evolves, these technical foundations may enable even more complex blockchain applications built upon Bitcoin's secure base layer.