Hi all,
I attempted to propose a BIP earlier today. I was notified of my incorrect actions versus core procedures.
See attached or below - my proposal for discussion.
Regards
Defenwycke.
---
A proposed discussion of segOP
29.10.2025
segOP (Segregated OP_RETURN)
A proposed extension to Bitcoin transactions. It introduces a dedicated, structured, full-fee data lane for on-chain data, without disrupting existing transaction rules. Think of it like this - segOP is to arbitrary data what SegWit was to signatures — a clean, isolated, forward-compatible path that preserves old-node harmony while restoring fee fairness.
Abstract:
segOP defines a new segregated data section for Bitcoin transactions, cryptographically committed via OP_SUCCESS184. It standardizes on-chain metadata storage by enforcing full fees, structured TLV encoding, and a 100 KB cap, while remaining backward-compatible with legacy nodes.
It is not:
- A replacement for OP_RETURN
- An off-chain mechanism
- A hard fork
It is:
- A soft-fork-safe, future-proof, SegWit-style data section
- Full-fee (4 weight units per byte)
- Structured (TLV + Merkle-root verified)
- Limited to 100 KB per transaction
What issues could segOP rectify?:
1. Ordinals abuse witness discount. segOP will apply full fee rate for large data.
2. No structured metadata lane. segOP introduces TLV-encoded + Merkle-verified section.
3. Witness discount abused for megabytes. segOP Enforces 100 KB cap.
4. OP_RETURN unstructured & limited. segOP = structured + verifiable.
5. Spam cheap storage. segOP deters spam with fees.
In short - segOP restores fairness — data pays its real weight cost, preserving block space for financial use.
Where segOP lives:
Transaction Layout (Post-segOP)
Transaction
├── nVersion
├── vin (inputs)
├── vout (outputs)
│ └── P2SOP Output ← segOP anchor
├── witness (if any)
├── segOP marker (0xFA)
├── segOP section (if present)
│ ├── chunk_count (varint)
│ ├── TLV chunk 1
│ ├── TLV chunk 2
│ └── ...
└── nLockTime
Activation rules:
- segOP section only appears if at least one P2SOP output exists.
- Old nodes ignore unknown post-witness data → transaction valid (soft-fork safe).
- New nodes validate the segOP section against the Merkle root in the P2SOP output.
How segOP works:
segOP extends the Bitcoin transaction format by adding a new optional section after the witness field.
This section is linked cryptographically to a special output type — the P2SOP output — whose script commits to the Merkle root of the segOP data.
The design mirrors SegWit: a segregated data structure, excluded from txid but included in wtxid, ensuring backward compatibility.
1. Transaction Creation
When a wallet or protocol wants to include on-chain structured data (for example, a document hash, timestamp, or proof set), it performs the following steps:
a. Build TLV Chunks
Each data element is encoded in Type-Length-Value (TLV) format:
- type (varint)
- length (varint)
- value (bytes)
Each type defines a data meaning (e.g., type=1: manifest, type=2: payload, type=3: metadata, etc.). This allows future extensions without breaking parsers.
b. Construct the Merkle Tree
Each TLV is hashed as:
leaf = dsha256(0x00 || TLV)
and combined recursively:
node = dsha256(0x01 || left || right)
until a single Merkle root is produced. This root uniquely commits to all TLV data while allowing compact partial proofs.
c. Commit to the Root (P2SOP Output)
The wallet then inserts a special output into the transaction: scriptPubKey = OP_SUCCESS184 0x20 <32-byte Merkle root> (OP_SUCCESS184 is reserved for soft-fork activation).
Legacy nodes treat it as “always true,” so the transaction remains spendable under pre-segOP rules.
The 32-byte push commits to the root of the segOP section.
Multiple P2SOP outputs may exist if a transaction carries multiple data trees, but each must be validated independently.
d. Serialize the segOP Section
After the witness data, a segOP marker (0xFA) signals presence, followed by the serialized data:
0xFA
varint: chunk_count
[TLV #1]
[TLV #2]
...
This section is included in the wtxid but not the txid, keeping legacy hashes unchanged (soft-fork compatible).
2. Transaction Relay and Policy
segOP transactions are relayed like any other, with a few policy rules:
- Size limit: The total size of segOP data (plus OP_RETURN + witness data >520 B) must not exceed 100,000 bytes. This prevents block bloat.
- Fee treatment: segOP data counts at 4 weight units per byte (no discount), restoring parity between data and signatures.
- Standardness check: Non-mining nodes enforce segOP as a standard policy rule (like SegWit’s P2WSH), rejecting noncompliant data from mempool relay.
These are policy rules, not consensus, but miners enforcing them makes segOP behavior uniform across the network.
3. Validation (Node-Level)
When a segOP transaction reaches a full node, validation happens in three stages:
a. Detect segOP Presence
- If any output script begins with OP_SUCCESS184, the node checks for a corresponding segOP section at the end of the transaction serialization.
- If no segOP section is found → transaction invalid under segOP rules.
b. Verify Size and Fee
The node computes total data size:
- All OP_RETURN payloads
- All segOP TLVs
- All witness items >520 bytes (these count as “data”)
- If this exceeds 100 KB, the transaction is invalid.
- The total weight is adjusted to include all segOP bytes at full cost.
c. Verify Merkle Root
- The node rebuilds the TLV Merkle tree and ensures:
- calculated_root == <root in P2SOP output>
- If the root mismatches → reject.
- This makes segOP cryptographically bound to the transaction body, just like Taproot commits to script paths.
4. Inclusion in a Block
- Miners include segOP transactions normally.
- When calculating block weight: segOP bytes count fully (4 WU/byte).
- segOP does not alter the legacy 4M weight limit but competes fairly for space.
- Miners can optionally expose segOP data through RPC or indexing APIs (e.g., gettxoutdata), similar to how they expose witness data.
5. Verification by Light Clients
- Because segOP uses a Merkle structure: SPV clients or oracles can request proofs for individual TLVs without downloading full data. For example, a timestamp verifier can request: getsegopproof <txid> <chunk_type> and receive the TLV + Merkle proof + root verification path. This makes segOP efficient for decentralized proof storage or timestamping protocols.
6. Spending a P2SOP Output
- Spending a P2SOP output works like spending an OP_SUCCESS output: Until activation, it behaves as anyone-can-spend, ensuring soft-fork safety. After activation, future consensus rules can restrict or redefine P2SOP redemption scripts.
- Example forward path: A future BIP may define OP_SUCCESS184 redemption to require proof of segOP validity or special conditions (e.g., hash preimage commitments). Until then, nodes treat these outputs as valid spends, ensuring no forks.
7. Post-Activation Behavior
- After segOP activation: All upgraded nodes enforce the 100 KB cap and Merkle root validation.
- Legacy nodes still accept the transactions, unaware of segOP structure.
- Any mismatch between segOP section and root simply makes the tx invalid for upgraded miners — thus ensuring consensus alignment.
Examples of segOP:
Example 1: Timestamp a Document (50 KB)
TLV #1: Type = 1, Manifest (JSON)
TLV #2: Type = 2, PDF payload (50 KB)
Build Merkle root → abc123...
Create output:
OP_SUCCESS184 0x20 abc123...
segOP section:
0x02 # chunk count
<TLV1> <TLV2>
Fee: ≈ $30 at current full-fee rates
Permanent, verifiable, structured.
Example 2: Ordinals Tries 3.8 MB
data_size = 3.8 MB → REJECTED (exceeds 100 KB cap)
Attempt in witness → REJECTED (data > 520 B → full fee policy → cap still enforced)
Example 3: Normal BTC Send
No P2SOP output : No segOP section
Fee Unchanged (~$0.09)
Normal transactions unaffected.
How to Use segOP:
Build a segOP Transaction (Python)
# 1. Prepare TLV chunks
manifest = b'{"type":"proof","size":50000}'
payload = b'50 KB of data...'
tlv1 = varint(1) + varint(len(manifest)) + manifest
tlv2 = varint(2) + varint(len(payload)) + payload
# 2. Build Merkle root
def dsha256(x): return sha256(sha256(x)).digest()
leaf1 = dsha256(b'\x00' + tlv1)
leaf2 = dsha256(b'\x00' + tlv2)
root = dsha256(b'\x01' + leaf1 + leaf2)
# 3. Create P2SOP output
p2sop = b'\xb8\x20' + root
# 4. Build segOP section
segop = b'\xFA' + varint(2) + tlv1 + tlv2 # 0xFA marker
# 5. Attach to tx
tx.vout.append(CTxOut(0, CScript(p2sop)))
tx.segop_section = segop
Validation Logic (C++ Pseudocode):
bool CheckSegOP(const CTransaction& tx) {
size_t total_data = 0;
for (const auto& out : tx.vout) {
if (out.scriptPubKey[0] == OP_SUCCESS184) {
// segOP output detected
if (!tx.HasSegOPSection()) return false;
total_data += tx.segOPSectionSize();
}
if (out.scriptPubKey[0] == OP_RETURN && out.scriptPubKey.size() > 1) {
total_data += out.scriptPubKey.size() - 1;
}
}
for (const auto& in : tx.vin) {
for (const auto& item : in.scriptWitness.stack) {
if (item.size() > 520)
total_data += item.size(); // witness data counts fully
}
}
if (total_data > 100000) return false; // 100 KB consensus cap
// Apply full weight to data for fee calc
tx.virtual_size += total_data;
return true;
}
Soft Fork Proof:
- Old node: Ignores segOP
- New node: Validates segOP
- No chain split
- Backward compatible
- Miner-activated soft fork possible via versionbits
Developer Q&A:
Where is segOP serialized? : After witness, before nLockTime
Does it affect txid? : No - only wtxid
Can old nodes parse it? : Yes (ignored like witness)
Max size? : 100 KB total data
Fee rate? : Full fee (4 WU/byte)
Can I use OP_RETURN too? : Yes — total combined data ≤ 100 KB
Future extensions? : TLV unknown types ignored (safe forward-compat)
How do I signal presence? : 0xFA marker after witness
Conclusion:
- On-chain
- Structured (TLV + Merkle)
- Full-fee and fair
- Soft-fork safe
- Future-proof
segOP introduces the clean, capped, verifiable data lane Bitcoin needs — ending witness discount abuse while preserving freedom for legitimate metadata.