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

Protocol Change Proposal: Taproot Envelope Data Encoding #3054

Open
adamkrellenstein opened this issue Feb 27, 2025 · 1 comment
Open

Protocol Change Proposal: Taproot Envelope Data Encoding #3054

adamkrellenstein opened this issue Feb 27, 2025 · 1 comment

Comments

@adamkrellenstein
Copy link
Member

adamkrellenstein commented Feb 27, 2025

Taproot Envelope Data Encoding

Motivation

Since its inception, one of Counterparty's main technical challenges has been efficiently storing data in the Bitcoin blockchain. Currently, two methods are predominantly used: OP_RETURN and multi-signature 2-of-3 outputs. The OP_RETURN method is limited to 80 bytes, while the multi-signature approach is both expensive and suboptimal from an architectural perspective.

With the introduction of Taproot addresses, we now have access to significantly more efficient and cost-effective methods. This specification outlines the implementation of the "Inscription envelope" method (popularized by Ordinals) as described in the official Ordinals documentation.

Technical Approach

Unlike existing methods which store data in transaction outputs, the envelope method stores data in the witnesses of transaction inputs. This offers substantial improvements in efficiency and cost.

Key Advantages

  • Increased Data Capacity: Overcome the 80-byte limitation of OP_RETURN
  • Reduced Costs: Lower fee requirements compared to multi-signature approaches
  • Cleaner Architecture: More elegant solution leveraging Bitcoin's latest capabilities

Implementation Methodology

For performance optimization, we don't want to check all witnesses of all transactions. Instead, we'll only examine inputs of transactions with an OP_RETURN containing the Counterparty prefix (only the prefix, without ID or data).

Step-by-Step Process

1. Commit Transaction

Create an output containing the public key tweaked with the envelope script:

# Build envelope script
data = binascii.hexlify("hello world!" * 3000.encode()).decode()
datas = helpers.chunkify(original_content, 520)
datas = [binascii.hexlify(data).decode("utf-8") for data in datas]
envelope_script = Script(["OP_FALSE", "OP_IF"] + datas + ["OP_ENDIF"])

# Build output
destination_address = source_pubkey.get_taproot_address([[envelope_script]])
tx_out = TxOutput(value, destination_address.to_script_pub_key())

The value amount will be calculated based on the data size, covering the fees necessary for the subsequent Reveal transaction.

Broadcast this first transaction (Commit) containing the previously created output.

2. Reveal Transaction

Create a second transaction (Reveal) with an input and an output:

tx_in = TxInput(commit_txid, commit_vout)
tx_out = TxOutput(0, Script(['OP_RETURN', b'CNTRPRTY']))

Sign the transaction including the complete envelope script that gets added to the witnesses:

reveal_tx.witnesses.append(
     TxWitnessInput([sig, envelope_script.to_hex(), control_block.to_hex()])
)

Broadcast the second transaction (Reveal).

3. Parsing

During parsing, if and only if a transaction has an OP_RETURN output containing the Counterparty prefix, retrieve the witness data:

# Extract the inscription script
inscription_script = Script.from_raw(verify_tx.witnesses[0].stack[1])

# Join all the chunks
inscription_data = "".join(inscription_script.script[2:-1])
inscription_content = binascii.unhexlify(inscription_data)

# Verify data integrity
assert inscription_content == original_content

Required Code Modifications

Transaction Parsing

Only RSFetcher needs to be modified:

  • In the parse_vout() function, when an OP_RETURN contains only the Counterparty prefix, data must be retrieved from the witnesses of the input.

Composer Changes

  • When encoding=p2tr is specified:

    • For segwit source addresses: Returns 2 transactions (Commit and Reveal) and the envelope script needed to sign the second transaction
    • For legacy addresses: Returns 1 transaction and the envelope script needed to sign the second transaction. The wallet will then need to use the new endpoint to compose the second transaction
  • New endpoint /v2/addresses/<address>/compose/reveal to compose the second transaction. The only required parameter is the txid of the commit transaction.

API Changes

  • Add p2tr as a valid value for the encoding parameter (will become the default in a future update)
  • Add envelope_script field in composition results when encoding=p2tr
  • Add commit_rawtransaction field in composition results when encoding=p2tr and the source is a segwit address
  • Add the endpoint /v2/addresses/<address>/compose/reveal

Important: The fees for the second transaction are determined when composing the first transaction. The fee configuration parameters are ignored by the /v2/addresses/<address>/compose/reveal endpoint.

Database Changes

No database changes are required for this implementation.

@adamkrellenstein adamkrellenstein changed the title Protocol Change Proposal: Taproot Data Encoding Protocol Change Proposal: Taproot Envelope Data Encoding Feb 27, 2025
@adamkrellenstein
Copy link
Member Author

adamkrellenstein commented Feb 28, 2025

Cost Comparison

Transaction Size Comparison

Size OP_RETURN P2TR MULTISIG P2SH
Bytes vBytes Bytes vBytes Bytes vBytes Bytes vBytes
10 212 212 353 239 303 303 295 241
16 218 218 359 240 303 303 301 247
32 234 234 375 244 303 303 317 263
64 266 266 407 252 303 303 349 295
80 282 282 423 256 415 415 365 311
128 N/A N/A 471 268 415 415 413 359
256 N/A N/A 599 300 639 639 541 487
1KB N/A N/A 1367 492 1983 1983 1309 1255
2KB N/A N/A 2391 748 3775 3775 2333 2279

Efficiency Ratio (vBytes per byte of data)

Size OP_RETURN P2TR MULTISIG P2TR vs MULTISIG P2SH P2TR vs P2SH
10 21.20 23.90 30.30 21% cheaper 24.10 1% cheaper
16 13.63 15.00 18.94 21% cheaper 15.44 3% cheaper
32 7.31 7.63 9.47 19% cheaper 8.22 7% cheaper
64 4.16 3.94 4.73 17% cheaper 4.61 15% cheaper
80 3.52 3.20 5.19 38% cheaper 3.89 18% cheaper
128 N/A 2.09 3.24 35% cheaper 2.80 25% cheaper
256 N/A 1.17 2.50 53% cheaper 1.90 38% cheaper
1KB N/A 0.48 1.94 75% cheaper 1.23 61% cheaper
2KB N/A 0.37 1.84 80% cheaper 1.11 67% cheaper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant